From 6722ef7fe9c9e71387efb47d8f9130ef2d4491fe Mon Sep 17 00:00:00 2001 From: Navin Date: Tue, 17 Nov 2020 18:09:09 +0530 Subject: [PATCH 01/12] =?UTF-8?q?docs(readme):=20=F0=9F=93=9D=20=20update?= =?UTF-8?q?=20readme=20with=20get=20started=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a0a7374bf..cca883721 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,92 @@ -# Renderless Components +

Renderless Components

-Accessible, composable, customizable renderless components powered by Reakit +

+ Collection of no-ui components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit System. +Explore all components ยป +

+ +

+ NPM version + NPM downloads + Build Status + Netlify Status
+ + License +

## Features +- Easy to compose - WAI-ARIA compatible - Keyboard accessible - Single HTML tag components - React Hooks everywhere -- Easy to style -- Easy to compose +- Easy to style using any framework + +## Installation + +```sh +# npm +npm install renderless-components reakit + +# Yarn +yarn add renderless-components reakit +``` + +> Make sure `react react-dom` is installed. + +## Usage + +```jsx +import React from "react"; +import { + Accordion, + AccordionPanel, + AccordionTrigger, + useAccordionState, +} from "renderless-components"; + +function App() { + const state = useAccordionState(); + + return ( + +

+ Trigger 1 +

+ Panel 1 +

+ Trigger 2 +

+ Panel 2 +
+ ); +} + +ReactDOM.render(, document.getElementById("root")); +``` + +Play with this on +[CodeSandbox](https://codesandbox.io/s/renderless-accordion-seywy) and read the +below documentation to learn more. + +## Components + +- Accordion +- Breadcrumbs +- Calendar +- Date Picker +- Drawer +- Link +- Meter +- Number Input +- Pagination +- Progress +- Select +- Slider +- Time Picker +- Toast ## License From bf45425aa8113db308b1459671900f3a461dd565 Mon Sep 17 00:00:00 2001 From: Navin Date: Tue, 17 Nov 2020 18:12:48 +0530 Subject: [PATCH 02/12] =?UTF-8?q?docs(readme):=20=F0=9F=93=9D=20=20remove?= =?UTF-8?q?=20code=20coverage=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cca883721..5581b1f1b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ System. NPM downloads Build Status Netlify Status
- License

From 679de64655a3a271b4c08ebd85e8335eecf79d53 Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 16:07:59 +0530 Subject: [PATCH 03/12] docs: add @navin-moorthy as a contributor --- .all-contributorsrc | 24 ++++++++++++++++++++++++ README.md | 28 +++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 .all-contributorsrc diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 000000000..5f4b8133b --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,24 @@ +{ + "projectName": "renderless-components", + "projectOwner": "timelessco", + "repoType": "github", + "repoHost": "https://github.com", + "files": [ + "README.md" + ], + "imageSize": 100, + "commit": true, + "commitConvention": "angular", + "contributors": [ + { + "login": "navin-moorthy", + "name": "Navin Moorthy", + "avatar_url": "https://avatars0.githubusercontent.com/u/39694575?v=4", + "profile": "https://navinmoorthy.me/", + "contributions": [ + "code" + ] + } + ], + "contributorsPerLine": 7 +} diff --git a/README.md b/README.md index 5581b1f1b..d89839fa3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@

Renderless Components

+ +[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) +

- Collection of no-ui components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit + Collection of headless components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit System. Explore all components ยป

@@ -90,3 +93,26 @@ below documentation to learn more. ## License MIT ยฉ [Timeless](https://timeless.co/) + +## Contributors โœจ + +Thanks goes to these wonderful people +([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + +

Navin Moorthy

๐Ÿ’ป
+ + + + + + +This project follows the +[all-contributors](https://github.com/all-contributors/all-contributors) +specification. Contributions of any kind welcome! From 66e611c7052ca7d531267b78be9f8ea6f97ea80f Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 16:08:10 +0530 Subject: [PATCH 04/12] docs: add @anuraghazra as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 5f4b8133b..1fd4a23f3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -18,6 +18,15 @@ "contributions": [ "code" ] + }, + { + "login": "anuraghazra", + "name": "Anurag Hazra", + "avatar_url": "https://avatars3.githubusercontent.com/u/35374649?v=4", + "profile": "http://anuraghazra.github.io/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index d89839fa3..a93f023d5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

Renderless Components

-[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-)

@@ -105,6 +105,7 @@ Thanks goes to these wonderful people +

Navin Moorthy

๐Ÿ’ป

Anurag Hazra

๐Ÿ’ป
From dde9faefbb28589f99c0da214dcc10369a1c693a Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 16:08:20 +0530 Subject: [PATCH 05/12] docs: add @sandeepprabhakaran as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1fd4a23f3..86e4f98e2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -27,6 +27,15 @@ "contributions": [ "code" ] + }, + { + "login": "sandeepprabhakaran", + "name": "Sandeep Prabhakaran", + "avatar_url": "https://avatars2.githubusercontent.com/u/6380293?v=4", + "profile": "http://timeless.co/", + "contributions": [ + "ideas" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index a93f023d5..1010df285 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

Renderless Components

-[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-)

@@ -106,6 +106,7 @@ Thanks goes to these wonderful people
Navin Moorthy

๐Ÿ’ป
Anurag Hazra

๐Ÿ’ป +
Sandeep Prabhakaran

๐Ÿค” From 2a5843ff4f5620b30dff32c2199e74c460230e3f Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 16:12:39 +0530 Subject: [PATCH 06/12] =?UTF-8?q?chore(contributor):=20=F0=9F=93=9D=20=20a?= =?UTF-8?q?dd=20all=20contributors=20of=20the=20project?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- package.json | 3 +++ yarn.lock | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1010df285..5c53e3782 100644 --- a/README.md +++ b/README.md @@ -90,10 +90,6 @@ below documentation to learn more. - Time Picker - Toast -## License - -MIT ยฉ [Timeless](https://timeless.co/) - ## Contributors โœจ Thanks goes to these wonderful people @@ -118,3 +114,7 @@ Thanks goes to these wonderful people This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + +## License + +MIT ยฉ [Timeless](https://timeless.co/) diff --git a/package.json b/package.json index c0da00e32..434f66538 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "build:types": "tsc --emitDeclarationOnly --project tsconfig.prod.json", "check-types": "yarn build:types && yarn tsd", "commit": "gacp", + "contributors:add": "all-contributors add", + "contributors:generate": "all-contributors generate", "format": "prettier --write \"./**/*.{js,ts,css,less,json,md,html,yml,yaml,pcss,jsx,tsx}\"", "generatejs": "node scripts/generate-js", "keys": "node scripts/build/keys", @@ -92,6 +94,7 @@ "@types/testing-library__jest-dom": "5.9.5", "@typescript-eslint/eslint-plugin": "4.6.0", "@typescript-eslint/parser": "4.6.0", + "all-contributors-cli": "^6.19.0", "babel-eslint": "10.1.0", "babel-jest": "^26.6.1", "babel-loader": "^8.1.0", diff --git a/yarn.lock b/yarn.lock index de8df3645..b14b18a18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1083,6 +1083,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.3.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -3661,6 +3668,22 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +all-contributors-cli@^6.19.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/all-contributors-cli/-/all-contributors-cli-6.19.0.tgz#7e4550973afede2476b62bd159fee6d72a1ad802" + integrity sha512-QJN4iLeTeYpTZJES8XFTzQ+itA1qSyBbxLapJLtwrnY+kipyRhCX49fS/s/qftQQym9XLATMZUpUeEeJSox1sw== + dependencies: + "@babel/runtime" "^7.7.6" + async "^3.0.1" + chalk "^4.0.0" + didyoumean "^1.2.1" + inquirer "^7.0.4" + json-fixer "^1.5.1" + lodash "^4.11.2" + node-fetch "^2.6.0" + pify "^5.0.0" + yargs "^15.0.1" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -4021,6 +4044,11 @@ async@^1.3.0: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= +async@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -6498,6 +6526,11 @@ detect-port@^1.3.0: address "^1.0.1" debug "^2.6.0" +didyoumean@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.1.tgz#e92edfdada6537d484d73c0172fd1eba0c4976ff" + integrity sha1-6S7f2tplN9SE1zwBcv0eugxJdv8= + diff-sequences@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" @@ -9207,7 +9240,7 @@ inquirer@^6.2.2: strip-ansi "^5.1.0" through "^2.3.6" -inquirer@^7.0.0: +inquirer@^7.0.0, inquirer@^7.0.4: version "7.3.3" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== @@ -10530,6 +10563,15 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-fixer@^1.5.1: + version "1.6.7" + resolved "https://registry.yarnpkg.com/json-fixer/-/json-fixer-1.6.7.tgz#90137a2053d5b4f43bed5419219605c02d38e094" + integrity sha512-fNkDto9hSiuofYNWuOd2G4FjlBiaUihWEWU3gSBSM+lfaynNmsRDijLcXxtnbuoxpU4erDHkMf0XUmoQ4SSEyA== + dependencies: + "@babel/runtime" "^7.12.1" + chalk "^4.1.0" + pegjs "^0.10.0" + json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -10940,7 +10982,7 @@ lodash.uniq@4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.20, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5, lodash@^4.2.1: +lodash@4.17.20, lodash@^4.0.1, lodash@^4.11.2, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5, lodash@^4.2.1: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -12588,6 +12630,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pegjs@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" + integrity sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -12613,6 +12660,11 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +pify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -16553,7 +16605,7 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: +yargs@^15.0.1, yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== From dbd3b6631a89f4a819a6ebae09680a1861bb65a7 Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 17:04:09 +0530 Subject: [PATCH 07/12] =?UTF-8?q?docs(accordion):=20=F0=9F=93=9D=20=20add?= =?UTF-8?q?=20docs=20for=20link,=20breadcrumb=20&=20accordion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 153 +++++++++++++++++++++++++++++++- src/accordion/Accordion.ts | 2 +- src/accordion/AccordionPanel.ts | 2 +- 3 files changed, 154 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c53e3782..ed0fa99f4 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ below documentation to learn more. ## Components -- Accordion +- [Accordion](#accordion) - Breadcrumbs - Calendar - Date Picker @@ -90,6 +90,157 @@ below documentation to learn more. - Time Picker - Toast +## Accordion + +Accessible Accordion component. It follows the +[WAI-ARIA Accordion Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion). + +### Usage + +```js +import { + Accordion, + AccordionPanel, + AccordionTrigger, + useAccordionState, +} from "renderless-components"; + +function Example() { + const state = useAccordionState(); + + return ( + +

+ Trigger 1 +

+ Panel 1 +

+ Trigger 2 +

+ Panel 2 +

+ Trigger 3 +

+ Panel 3 +

+ Trigger 4 +

+ Panel 4 +

+ Trigger 5 +

+ Panel 5 + + ); +} +``` + +### Accessibility + +- `Accordion` extends the accessibility features of + [Composite](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionTrigger` has role `button`. +- `AccordionTrigger` has `aria-controls` referring to its associated + `AccordionPanel`. +- `AccordionTrigger` has `aria-expanded` set to `true` when it's associated + `AccordionPanel` is expanded. +- Each `AccordionTrigger` should be wrapped in an element with role `heading`. +- `AccordionTrigger` extends the accessibility features of + [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionPanel` has `aria-labelledby` referring to its associated + `AccordionTrigger`. +- `AccordionPanel` extends the accessibility features of + [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). + +### Composition + +- `Accordion` uses + [Composite](https://github.com/reakit/reakit/blob/master/docs/composite). +- `AccordionTrigger` uses + [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite). +- `AccordionPanel` uses + [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). + +## Link + +Accessible `Link` component that provides the required aria role when used under +different compositions. It follows the +[WAI-ARIA Link Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#link). + +### Usage + +```js +import { Link } from "renderless-components"; + +function Example() { + return Link; +} +``` + +### Accessibilty + +- `Link` has role `link`. + +### Composition + +- `Link` uses + [Clickable](https://github.com/reakit/reakit/blob/master/docs/clickable) + +## Breadcrumb + +Accessible `Breadcrumb` component that provides the required aria attributes for +it's links. It follows the +[WAI-ARIA Breadcrumb Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#breadcrumb). + +### Usage + +```js +import { Breadcrumbs, BreadcrumbLink } from "renderless-components"; + +function Example() { + return ( + +
    +
  1. + + WAI-ARIA Authoring Practices 1.1 + +
  2. +
  3. + + Design Patterns + +
  4. +
  5. + + Breadcrumb Pattern + +
  6. +
  7. + + Breadcrumb Example + +
  8. +
+
+ ); +} +``` + +### Accessibilty + +- `Breadcrumbs` should have `aria-label` or `aria-labelledby` attribute. +- `BreadcrumbLink` should have `aria-current` set to `page` if the currenct page + is loaded. +- `BreadcrumbLink` extends the accessibility features of [Link](#Link). + +### Composition + +- `BreadcrumbLink` uses [Link](#Link). + ## Contributors โœจ Thanks goes to these wonderful people diff --git a/src/accordion/Accordion.ts b/src/accordion/Accordion.ts index c332e10f3..f32610b10 100644 --- a/src/accordion/Accordion.ts +++ b/src/accordion/Accordion.ts @@ -30,6 +30,6 @@ export const useAccordion = createHook({ export const Accordion = createComponent({ as: "div", - useHook: useAccordion, memo: true, + useHook: useAccordion, }); diff --git a/src/accordion/AccordionPanel.ts b/src/accordion/AccordionPanel.ts index 9176a3f3d..e53f01b7c 100644 --- a/src/accordion/AccordionPanel.ts +++ b/src/accordion/AccordionPanel.ts @@ -61,7 +61,6 @@ export const useAccordionPanel = createHook< return { ref: useForkRef(ref, htmlRef), - role: "region", "aria-labelledby": accordionId, ...htmlProps, }; @@ -77,6 +76,7 @@ export const useAccordionPanel = createHook< export const AccordionPanel = createComponent({ as: "div", + memo: true, useHook: useAccordionPanel, }); From 44397dbcdb053496c059adead9e8b1978e5a860c Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 18 Nov 2020 17:17:48 +0530 Subject: [PATCH 08/12] =?UTF-8?q?chore(accordion):=20=E2=9C=85=20=20update?= =?UTF-8?q?=20snapshot=20for=20accordion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap b/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap index ded535791..664057a92 100644 --- a/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +++ b/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap @@ -20,7 +20,6 @@ exports[`Accordion should render correctly 1`] = ` aria-labelledby="accordion-1" hidden="" id="accordion-3" - role="region" style="display: none;" > panel 1 @@ -40,7 +39,6 @@ exports[`Accordion should render correctly 1`] = ` aria-labelledby="accordion-2" hidden="" id="accordion-6" - role="region" style="display: none;" > panel 2 @@ -60,7 +58,6 @@ exports[`Accordion should render correctly 1`] = ` aria-labelledby="accordion-7" hidden="" id="accordion-9" - role="region" style="display: none;" > panel 3 @@ -82,7 +79,6 @@ exports[`Accordion should render correctly 1`] = ` aria-labelledby="accordion-10" hidden="" id="accordion-12" - role="region" style="display: none;" > disabled panel From d4664757a77b835ec139b82120fee8ced52055ec Mon Sep 17 00:00:00 2001 From: Anurag Date: Wed, 18 Nov 2020 17:54:48 +0530 Subject: [PATCH 09/12] chore: added some emojis --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ed0fa99f4..03dd3afd5 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,13 @@ System. ## Features -- Easy to compose -- WAI-ARIA compatible -- Keyboard accessible -- Single HTML tag components -- React Hooks everywhere -- Easy to style using any framework - -## Installation +- Accessible :wheelchair: +- Composable :toolbox: +- WAI-ARIA Compatible :spiral_notepad: +- React Hooks Based :anchor: +- Easy To Customize, Style & Extend :nail_care: + +## :rocket: Installation ```sh # npm From 94873964773650085f7a1647416b74ded92a6640 Mon Sep 17 00:00:00 2001 From: Anurag Hazra Date: Wed, 2 Dec 2020 17:34:17 +0530 Subject: [PATCH 10/12] docs: added docs generation script (#157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: added docs generation script * docs: change readme doc layout * docs: added props,csblink,composition,example generation script (#160) * chore(accordion): refactored & cleaned up accordion types (#153) * test(select): added select tests (#154) * test(select): added test for select component * test(select): added typeahead tests * chore: window.setTimeout -> setTimeout * chore: fix comment * test(select): added multi select tests * chore: moduleNameWrapper for renderless-component in jest * chore: try fix * chore: update import path * chore: wip prop generation * docs: fixed props types generator script * chore: removed redundant utils code * chore: outdent template strings * chore: unify getJsDocs function * chore: added inject-md-content script * docs: run docsgen:example & docsgen:props * build(props-docgen): ๐Ÿ› fix rangecalendar types * chore: accordion types reorder * chore: run prettier on markdown * chore: fixed perttier not working * docs: added composition generation script * docs: added prettify script and run once * refactor: refactored inject prop script * chore(accordion): ๐Ÿท๏ธ update type declaration for prop generation (#163) * chore: regenerate docs * docs: added codesandbox link generation script * docs: improve sandbox script to add short sandbox url * docs: hardcode reakit dep & fixed extraDep * docs(calendar): ๐Ÿ“ update jsdocs for the calendar (#166) * docs(calendar): ๐Ÿ“ update jsdocs for the calendar * docs(calendar): ๐Ÿ“ update the examples with headings * docs: added calendar sandbox link * docs: added link_title support for csblinks generation * docs: added support for multiple csb links * chore: rename fsUtils to fs-utils * docs: added links in main readme * fix(docs): refactored & fixed multiple sandbox link generation * docs: fix csblinks path & regenerate docs * chore: renamed generate-docs to inject-examples & better chalk logs Co-authored-by: Navin * docs: getting started and guides documentation (#170) * docs: guidelines and getting started docs * docs: fix links * docs(datepicker): added docs for datepicker * docs: fix accidental prop/compose generation in code-base-overview docs * docs(readme): ๐Ÿ“ add docs for all the components (#171) * docs(rename): ๐Ÿ“ files on the git * docs: ๐Ÿ“ improve docs spellings and wordings Co-authored-by: Navin Moorthy * docs(scripts): ๐Ÿ“ use scripts to generate docs * refactor(docs): ๐Ÿ“ improve docs scripts * docs: fixed docs gen multiple csblinks (#172) * docs: fix csb multiple links generation * docs: remove line ending on examples & added progress logs in gen script Co-authored-by: Navin --- README.md | 224 +---- docs-templates/accordion.md | 42 + docs-templates/breadcrumb.md | 26 + docs-templates/calendar.md | 37 + docs-templates/datepicker.md | 37 + docs-templates/drawer.md | 22 + docs-templates/link.md | 23 + docs-templates/meter.md | 23 + docs-templates/number-input.md | 22 + docs-templates/pagination.md | 22 + docs-templates/picker-base.md | 22 + docs-templates/progress.md | 23 + docs-templates/segment.md | 22 + docs-templates/select.md | 23 + docs-templates/slider.md | 23 + docs-templates/timepicker.md | 23 + docs-templates/toast.md | 23 + docs/accordion.md | 338 +++++++ docs/breadcrumb.md | 77 ++ docs/calendar.md | 437 +++++++++ docs/code-base-overview.md | 122 +++ docs/core-principles.md | 43 + docs/datepicker.md | 535 +++++++++++ docs/drawer.md | 149 ++++ docs/getting-started.md | 78 ++ docs/link.md | 39 + docs/meter.md | 145 +++ docs/number-input.md | 180 ++++ docs/pagination.md | 139 +++ docs/picker-base.md | 129 +++ docs/progress.md | 174 ++++ docs/segment.md | 200 +++++ docs/select.md | 755 ++++++++++++++++ docs/slider.md | 273 ++++++ docs/timepicker.md | 832 ++++++++++++++++++ docs/toast.md | 54 ++ package.json | 15 +- scripts/builds/docs.js | 49 ++ scripts/{build => builds}/keys.js | 0 scripts/generate-js.js | 50 +- scripts/utils/fs-utils.js | 54 ++ scripts/{utils.js => utils/index.js} | 23 +- scripts/utils/inject-composition.js | 95 ++ scripts/utils/inject-csb-links.js | 116 +++ scripts/utils/inject-examples.js | 31 + scripts/utils/inject-md-content.js | 14 + scripts/utils/inject-props.js | 199 +++++ scripts/utils/md-prettify.js | 14 + src/accordion/Accordion.ts | 12 +- src/accordion/AccordionPanel.ts | 105 +-- src/accordion/AccordionState.ts | 31 +- src/accordion/AccordionTrigger.ts | 58 +- src/accordion/helpers.ts | 77 ++ .../stories/AccordionBasic.stories.tsx | 4 +- .../stories/AccordionStyled.stories.tsx | 5 +- src/accordion/types.ts | 34 +- src/breadcrumbs/BreadcrumbLink.ts | 24 +- src/breadcrumbs/Breadcrumbs.ts | 12 +- src/calendar/Calendar.ts | 14 +- src/calendar/CalendarButton.ts | 44 +- src/calendar/CalendarCell.ts | 30 +- src/calendar/CalendarCellButton.ts | 46 +- src/calendar/CalendarGrid.ts | 52 +- src/calendar/CalendarHeader.ts | 20 +- src/calendar/CalendarState.ts | 170 +++- src/calendar/CalendarWeekTitle.ts | 20 +- src/calendar/RangeCalendarState.ts | 50 +- src/calendar/helpers/useWeekStart.ts | 4 +- yarn.lock | 287 +++++- 69 files changed, 6502 insertions(+), 593 deletions(-) create mode 100644 docs-templates/accordion.md create mode 100644 docs-templates/breadcrumb.md create mode 100644 docs-templates/calendar.md create mode 100644 docs-templates/datepicker.md create mode 100644 docs-templates/drawer.md create mode 100644 docs-templates/link.md create mode 100644 docs-templates/meter.md create mode 100644 docs-templates/number-input.md create mode 100644 docs-templates/pagination.md create mode 100644 docs-templates/picker-base.md create mode 100644 docs-templates/progress.md create mode 100644 docs-templates/segment.md create mode 100644 docs-templates/select.md create mode 100644 docs-templates/slider.md create mode 100644 docs-templates/timepicker.md create mode 100644 docs-templates/toast.md create mode 100644 docs/accordion.md create mode 100644 docs/breadcrumb.md create mode 100644 docs/calendar.md create mode 100644 docs/code-base-overview.md create mode 100644 docs/core-principles.md create mode 100644 docs/datepicker.md create mode 100644 docs/drawer.md create mode 100644 docs/getting-started.md create mode 100644 docs/link.md create mode 100644 docs/meter.md create mode 100644 docs/number-input.md create mode 100644 docs/pagination.md create mode 100644 docs/picker-base.md create mode 100644 docs/progress.md create mode 100644 docs/segment.md create mode 100644 docs/select.md create mode 100644 docs/slider.md create mode 100644 docs/timepicker.md create mode 100644 docs/toast.md create mode 100644 scripts/builds/docs.js rename scripts/{build => builds}/keys.js (100%) create mode 100644 scripts/utils/fs-utils.js rename scripts/{utils.js => utils/index.js} (97%) create mode 100644 scripts/utils/inject-composition.js create mode 100644 scripts/utils/inject-csb-links.js create mode 100644 scripts/utils/inject-examples.js create mode 100644 scripts/utils/inject-md-content.js create mode 100644 scripts/utils/inject-props.js create mode 100644 scripts/utils/md-prettify.js create mode 100644 src/accordion/helpers.ts diff --git a/README.md b/README.md index 03dd3afd5..001391dce 100644 --- a/README.md +++ b/README.md @@ -37,208 +37,28 @@ yarn add renderless-components reakit > Make sure `react react-dom` is installed. -## Usage - -```jsx -import React from "react"; -import { - Accordion, - AccordionPanel, - AccordionTrigger, - useAccordionState, -} from "renderless-components"; - -function App() { - const state = useAccordionState(); - - return ( - -

- Trigger 1 -

- Panel 1 -

- Trigger 2 -

- Panel 2 -
- ); -} - -ReactDOM.render(, document.getElementById("root")); -``` - -Play with this on -[CodeSandbox](https://codesandbox.io/s/renderless-accordion-seywy) and read the -below documentation to learn more. - -## Components - -- [Accordion](#accordion) -- Breadcrumbs -- Calendar -- Date Picker -- Drawer -- Link -- Meter -- Number Input -- Pagination -- Progress -- Select -- Slider -- Time Picker -- Toast - -## Accordion - -Accessible Accordion component. It follows the -[WAI-ARIA Accordion Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion). - -### Usage - -```js -import { - Accordion, - AccordionPanel, - AccordionTrigger, - useAccordionState, -} from "renderless-components"; - -function Example() { - const state = useAccordionState(); - - return ( - -

- Trigger 1 -

- Panel 1 -

- Trigger 2 -

- Panel 2 -

- Trigger 3 -

- Panel 3 -

- Trigger 4 -

- Panel 4 -

- Trigger 5 -

- Panel 5 -
- ); -} -``` - -### Accessibility - -- `Accordion` extends the accessibility features of - [Composite](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). -- `AccordionTrigger` has role `button`. -- `AccordionTrigger` has `aria-controls` referring to its associated - `AccordionPanel`. -- `AccordionTrigger` has `aria-expanded` set to `true` when it's associated - `AccordionPanel` is expanded. -- Each `AccordionTrigger` should be wrapped in an element with role `heading`. -- `AccordionTrigger` extends the accessibility features of - [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). -- `AccordionPanel` has `aria-labelledby` referring to its associated - `AccordionTrigger`. -- `AccordionPanel` extends the accessibility features of - [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). - -### Composition - -- `Accordion` uses - [Composite](https://github.com/reakit/reakit/blob/master/docs/composite). -- `AccordionTrigger` uses - [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite). -- `AccordionPanel` uses - [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). - -## Link - -Accessible `Link` component that provides the required aria role when used under -different compositions. It follows the -[WAI-ARIA Link Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#link). - -### Usage - -```js -import { Link } from "renderless-components"; - -function Example() { - return Link; -} -``` - -### Accessibilty - -- `Link` has role `link`. - -### Composition - -- `Link` uses - [Clickable](https://github.com/reakit/reakit/blob/master/docs/clickable) - -## Breadcrumb - -Accessible `Breadcrumb` component that provides the required aria attributes for -it's links. It follows the -[WAI-ARIA Breadcrumb Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#breadcrumb). - -### Usage - -```js -import { Breadcrumbs, BreadcrumbLink } from "renderless-components"; - -function Example() { - return ( - -
    -
  1. - - WAI-ARIA Authoring Practices 1.1 - -
  2. -
  3. - - Design Patterns - -
  4. -
  5. - - Breadcrumb Pattern - -
  6. -
  7. - - Breadcrumb Example - -
  8. -
-
- ); -} -``` - -### Accessibilty - -- `Breadcrumbs` should have `aria-label` or `aria-labelledby` attribute. -- `BreadcrumbLink` should have `aria-current` set to `page` if the currenct page - is loaded. -- `BreadcrumbLink` extends the accessibility features of [Link](#Link). - -### Composition - -- `BreadcrumbLink` uses [Link](#Link). +## Getting started + +Check out our [getting started docs](/docs/getting-started.md) + +## Component Docs + +- [Accordion](docs/accordion.md) +- [Breadcrumbs](docs/breadcrumb.md) +- [Calendar](docs/calendar.md) +- [Date Picker](docs/datepicker.md) +- [Drawer](docs/drawer.md) +- [Link](docs/Link.md) +- [Meter](docs/meter.md) +- [Number Input](docs/number-input.md) +- [Pagination](docs/pagination.md) +- [Picker Base](docs/picker-base.md) +- [Progress](docs/progress.md) +- [Segment](docs/segment.md) +- [Select](docs/select.md) +- [Slider](docs/slider.md) +- [Time Picker](docs/timepicker.md) +- [Toast](docs/toast.md) ## Contributors โœจ diff --git a/docs-templates/accordion.md b/docs-templates/accordion.md new file mode 100644 index 000000000..16e9dd98c --- /dev/null +++ b/docs-templates/accordion.md @@ -0,0 +1,42 @@ +## Accordion + +Accessible Accordion component. It follows the +[WAI-ARIA Accordion Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion). + + + +## Props + + + +## Accessibility + +- `Accordion` extends the accessibility features of + [Composite](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionTrigger` has role `button`. +- `AccordionTrigger` has `aria-controls` referring to its associated + `AccordionPanel`. +- `AccordionTrigger` has `aria-expanded` set to `true` when it's associated + `AccordionPanel` is expanded. +- Each `AccordionTrigger` should be wrapped in an element with role `heading`. +- `AccordionTrigger` extends the accessibility features of + [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionPanel` has `aria-labelledby` referring to its associated + `AccordionTrigger`. +- `AccordionPanel` extends the accessibility features of + [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/breadcrumb.md b/docs-templates/breadcrumb.md new file mode 100644 index 000000000..4013e4bd1 --- /dev/null +++ b/docs-templates/breadcrumb.md @@ -0,0 +1,26 @@ +## Breadcrumb + +Accessible `Breadcrumb` component that provides the required aria attributes for +it's links. It follows the +[WAI-ARIA Breadcrumb Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#breadcrumb). + +## Props + + + +## Accessibilty + +- `Breadcrumbs` should have `aria-label` or `aria-labelledby` attribute. +- `BreadcrumbLink` should have `aria-current` set to `page` if the currenct page + is loaded. +- `BreadcrumbLink` extends the accessibility features of [Link](#Link). + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/calendar.md b/docs-templates/calendar.md new file mode 100644 index 000000000..2a8b97325 --- /dev/null +++ b/docs-templates/calendar.md @@ -0,0 +1,37 @@ +## Calendar + +Accessible `Calendar` component. + + + + + +## Props + + + +## Composition + + + +## Example + +### Base Calendar + +```js + +``` + +### Range Calendar + +```js + +``` diff --git a/docs-templates/datepicker.md b/docs-templates/datepicker.md new file mode 100644 index 000000000..0ba1a9498 --- /dev/null +++ b/docs-templates/datepicker.md @@ -0,0 +1,37 @@ +## DatePicker + +Accessible `DatePicker` component. + + + + + +## Props + + + +## Composition + + + +## Example + +### DatePicker + +```js + +``` + +### Range Date Picker + +```js + +``` diff --git a/docs-templates/drawer.md b/docs-templates/drawer.md new file mode 100644 index 000000000..322f64648 --- /dev/null +++ b/docs-templates/drawer.md @@ -0,0 +1,22 @@ +## Drawer + +Accessible `Drawer` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/link.md b/docs-templates/link.md new file mode 100644 index 000000000..76e6034f6 --- /dev/null +++ b/docs-templates/link.md @@ -0,0 +1,23 @@ +## Link + +Accessible `Link` component that provides the required aria role when used under +different compositions. It follows the +[WAI-ARIA Link Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#link). + +## Props + + + +## Accessibilty + +- `Link` has role `link`. + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/meter.md b/docs-templates/meter.md new file mode 100644 index 000000000..3bb4bb185 --- /dev/null +++ b/docs-templates/meter.md @@ -0,0 +1,23 @@ +## Meter + +Accessible `Meter` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/number-input.md b/docs-templates/number-input.md new file mode 100644 index 000000000..a25a37ae4 --- /dev/null +++ b/docs-templates/number-input.md @@ -0,0 +1,22 @@ +## NumberInput + +Accessible `NumberInput` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/pagination.md b/docs-templates/pagination.md new file mode 100644 index 000000000..b6c83bef3 --- /dev/null +++ b/docs-templates/pagination.md @@ -0,0 +1,22 @@ +## Pagination + +Accessible `Pagination` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/picker-base.md b/docs-templates/picker-base.md new file mode 100644 index 000000000..2489c937f --- /dev/null +++ b/docs-templates/picker-base.md @@ -0,0 +1,22 @@ +## PickerBase + +Accessible `PickerBase` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/progress.md b/docs-templates/progress.md new file mode 100644 index 000000000..f76e78f69 --- /dev/null +++ b/docs-templates/progress.md @@ -0,0 +1,23 @@ +## Progress + +Accessible `Progress` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/segment.md b/docs-templates/segment.md new file mode 100644 index 000000000..3d02e6550 --- /dev/null +++ b/docs-templates/segment.md @@ -0,0 +1,22 @@ +## Segment + +Accessible `Segment` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/select.md b/docs-templates/select.md new file mode 100644 index 000000000..d8bf8cfba --- /dev/null +++ b/docs-templates/select.md @@ -0,0 +1,23 @@ +## Select + +Accessible `Select` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/slider.md b/docs-templates/slider.md new file mode 100644 index 000000000..1a1556da3 --- /dev/null +++ b/docs-templates/slider.md @@ -0,0 +1,23 @@ +## Slider + +Accessible `Slider` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/timepicker.md b/docs-templates/timepicker.md new file mode 100644 index 000000000..8febd3975 --- /dev/null +++ b/docs-templates/timepicker.md @@ -0,0 +1,23 @@ +## TimePicker + +Accessible `TimePicker` component. + + + +## Props + + + +## Composition + + + +## Example + +```js + +``` diff --git a/docs-templates/toast.md b/docs-templates/toast.md new file mode 100644 index 000000000..8f556a01c --- /dev/null +++ b/docs-templates/toast.md @@ -0,0 +1,23 @@ +## Toast + +Accessible `Toast` component. + + + + + +## Example + +```js + +``` diff --git a/docs/accordion.md b/docs/accordion.md new file mode 100644 index 000000000..31de0149a --- /dev/null +++ b/docs/accordion.md @@ -0,0 +1,338 @@ +## Accordion + +Accessible Accordion component. It follows the +[WAI-ARIA Accordion Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion). + +[Accordion Example Live Demo](https://codesandbox.io/s/qvgg2) + +## Props + + + +### `useAccordionState` + +- **`allowMultiple`** false | undefined Allow to open multiple + accordion items +- **`manual`** boolean Whether the accodion selection should be + manual. +- **`allowToggle`** boolean Allow to toggle accordion items +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. + +### `Accordion` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
12 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. + +
+ +### `AccordionPanel` + +- **`accordionId`** string | undefined Accordion's id +- **`visible`** boolean Whether it's visible or not. +- **`animating`** boolean Whether it's animating or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`id`** string | undefined Same as the HTML attribute. +
8 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`allowMultiple`** boolean Allow to open multiple accordion + items +- **`selectedId`** string | null | undefined The current selected + accordion's `id`. +- **`selectedIds`** (string | null)[] | undefined The current + selected accordion's `id`. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`registerPanel`** (item: Item) => void Registers a + accordion panel. +- **`unregisterPanel`** (id: string) => void Unregisters a + accordion panel. +- **`panels`** Item[] Lists all the panels. + +
+ +### `AccordionTrigger` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +
23 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`manual`** boolean Whether the accodion selection should be + manual. +- **`allowMultiple`** boolean Allow to open multiple accordion + items +- **`selectedId`** string | null | undefined The current selected + accordion's `id`. +- **`allowToggle`** boolean Allow to toggle accordion items +- **`selectedIds`** (string | null)[] | undefined The current + selected accordion's `id`. +- **`panels`** Item[] Lists all the panels. +- **`select`** (id: string | null) => void Moves into and + selects an accordion by its `id`. +- **`unSelect`** (id: string | null) => void Moves into and + unSelects an accordion by its `id` if it's already selected. + +
+ +## Accessibility + +- `Accordion` extends the accessibility features of + [Composite](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionTrigger` has role `button`. +- `AccordionTrigger` has `aria-controls` referring to its associated + `AccordionPanel`. +- `AccordionTrigger` has `aria-expanded` set to `true` when it's associated + `AccordionPanel` is expanded. +- Each `AccordionTrigger` should be wrapped in an element with role `heading`. +- `AccordionTrigger` extends the accessibility features of + [CompositeItem](https://github.com/reakit/reakit/blob/master/docs/composite/#accessibility). +- `AccordionPanel` has `aria-labelledby` referring to its associated + `AccordionTrigger`. +- `AccordionPanel` extends the accessibility features of + [DisclosureContent](https://github.com/reakit/reakit/blob/master/docs/disclosure). + +## Composition + +- Accordion uses [useComposite](https://reakit.io/docs/composite) +- AccordionPanel uses [unstable_useId](https://reakit.io/docs/id) and + [useDisclosureContent](https://reakit.io/docs/disclosure) +- AccordionTrigger uses [useButton](https://reakit.io/docs/button) and + [useCompositeItem](https://reakit.io/docs/composite) + +## Example + +```js +import * as React from "react"; + +import { + Accordion, + AccordionPanel, + AccordionTrigger, + useAccordionState, +} from "renderless-components"; + +export function App(props) { + const state = useAccordionState(props); + + return ( + +

+ Trigger 1 +

+ Panel 1 +

+ Trigger 2 +

+ Panel 2 +

+ + Trigger 3 + +

+ Panel 3 +

+ Trigger 4 +

+ Panel 4 +

+ Trigger 5 +

+ Panel 5 +
+ ); +} + +export default App; +``` diff --git a/docs/breadcrumb.md b/docs/breadcrumb.md new file mode 100644 index 000000000..59711184b --- /dev/null +++ b/docs/breadcrumb.md @@ -0,0 +1,77 @@ +## Breadcrumb + +Accessible `Breadcrumb` component that provides the required aria attributes for +it's links. It follows the +[WAI-ARIA Breadcrumb Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#breadcrumb). + +## Props + + + +### `BreadcrumbLink` + +- **`isCurrent`** boolean | undefined If true, sets + `aria-current: "page"` +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`isExternal`** boolean | undefined Opens the link in a new tab + +### `Breadcrumbs` + +No props to show + +## Accessibilty + +- `Breadcrumbs` should have `aria-label` or `aria-labelledby` attribute. +- `BreadcrumbLink` should have `aria-current` set to `page` if the currenct page + is loaded. +- `BreadcrumbLink` extends the accessibility features of [Link](#Link). + +## Composition + +- BreadcrumbLink uses [useLink](./link.md) +- Breadcrumbs uses [useBox](https://reakit.io/docs/box) + +## Example + +```js +import * as React from "react"; + +import { Breadcrumbs, BreadcrumbLink } from "renderless-components"; + +export const App = props => { + return ( + +
    +
  1. + + WAI-ARIA Authoring Practices 1.1 + +
  2. +
  3. + + Design Patterns + +
  4. +
  5. + + Breadcrumb Pattern + +
  6. +
  7. + + Breadcrumb Example + +
  8. +
+
+ ); +}; + +export default App; +``` diff --git a/docs/calendar.md b/docs/calendar.md new file mode 100644 index 000000000..f6d7810ae --- /dev/null +++ b/docs/calendar.md @@ -0,0 +1,437 @@ +## Calendar + +Accessible `Calendar` component. + +[RangeCalendar - Open On Sandbox](https://codesandbox.io/s/khdp2) + +[Calendar - Open On Sandbox](https://codesandbox.io/s/pmtcs) + +## Props + + + +### `useCalendarState` + +- **`value`** T | undefined The current value (controlled). +- **`defaultValue`** T | undefined The default value + (uncontrolled). +- **`onChange`** ((value: T) => void) | undefined Handler that + is called when the value changes. +- **`minValue`** T | undefined The smallest value allowed. +- **`maxValue`** T | undefined The largest value allowed. +- **`isDisabled`** boolean | undefined Whether the input is + disabled. +- **`isReadOnly`** boolean | undefined Whether the input can be + selected but not changed by the user. +- **`autoFocus`** boolean | undefined Whether the element should + receive focus on render. +- **`id`** string | undefined Id for the calendar grid + +### `useRangeCalendarState` + +- **`value`** T | undefined The current value (controlled). +- **`defaultValue`** T | undefined The default value + (uncontrolled). +- **`onChange`** ((value: T) => void) | undefined Handler that + is called when the value changes. +- **`minValue`** T | undefined The smallest value allowed. +- **`maxValue`** T | undefined The largest value allowed. +- **`isDisabled`** boolean | undefined Whether the input is + disabled. +- **`isReadOnly`** boolean | undefined Whether the input can be + selected but not changed by the user. +- **`autoFocus`** boolean | undefined Whether the element should + receive focus on render. +- **`id`** string | undefined Id for the calendar grid + +### `Calendar` + +
1 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`calendarId`** string | undefined Id for the Calendar Header + +
+ +### `CalendarButton` + +- **`goto`** + "nextMonth" + | "previousMonth" | "nextYear" | "p... + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
4 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`focusNextMonth`** () => void Focus the cell one month next + to the current date +- **`focusPreviousMonth`** () => void Focus the cell one month + prev to the current date +- **`focusPreviousYear`** () => void Focus the cell of the date + one year before the current date +- **`focusNextYear`** () => void Focus the cell of the date one + year from the current date + +
+ +### `CalendarCell` + +- **`date`** Date + +
6 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`dateValue`** Date Selected Date value +- **`isDisabled`** boolean `true` if the calendar is disabled +- **`currentMonth`** Date Month of the current Date +- **`isRangeCalendar`** boolean `true` if the calendar is used as + RangeCalendar +- **`highlightDate`** (date: Date) => void + +- **`highlightedRange`** RangeValue<Date> | null + +
+ +### `CalendarCellButton` + +- **`date`** Date + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
11 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`dateValue`** Date Selected Date value +- **`isDisabled`** boolean `true` if the calendar is disabled +- **`isRangeCalendar`** boolean `true` if the calendar is used as + RangeCalendar +- **`focusedDate`** Date Date value that is currently focused +- **`selectDate`** (value: Date) => void sets `dateValue` +- **`setFocusedDate`** (value: SetStateAction<Date>) => + void Sets `focusedDate` +- **`month`** number Month of the current date value +- **`minDate`** Date | undefined Minimum allowed Date value +- **`maxDate`** Date | undefined Maximum allowed Date value +- **`isFocused`** boolean `true` if the calendar is focused +- **`anchorDate`** Date | null + +
+ +### `CalendarGrid` + +
17 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`calendarId`** string | undefined Id for the Calendar Header +- **`focusNextMonth`** () => void Focus the cell one month next + to the current date +- **`focusPreviousMonth`** () => void Focus the cell one month + prev to the current date +- **`focusPreviousYear`** () => void Focus the cell of the date + one year before the current date +- **`focusNextYear`** () => void Focus the cell of the date one + year from the current date +- **`isDisabled`** boolean `true` if the calendar is disabled +- **`isRangeCalendar`** boolean `true` if the calendar is used as + RangeCalendar +- **`isReadOnly`** boolean `true` if the calendar is only readonly +- **`setFocused`** (value: SetStateAction<boolean>) => + void Sets `isFocused` +- **`selectFocusedDate`** () => void Selects the `focusedDate` +- **`focusEndOfMonth`** () => void Focus the cell of the last + day of the month +- **`focusStartOfMonth`** () => void Focus the cell of the + first day of the month +- **`focusNextDay`** () => void Focus the cell next to the + current date +- **`focusPreviousDay`** () => void Focus the cell prev to the + current date +- **`focusNextWeek`** () => void Focus the cell one week next + to the current date +- **`focusPreviousWeek`** () => void Focus the cell one week + prev to the current date +- **`setAnchorDate`** (value: SetStateAction<Date | null>) => + void + +
+ +### `CalendarHeader` + +- **`format`** DateTimeFormatOpts | undefined + +
2 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`calendarId`** string | undefined Id for the Calendar Header +- **`currentMonth`** Date Month of the current Date + +
+ +### `CalendarWeekTitle` + +- **`dayIndex`** number + +
1 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`weekDays`** { title: string; abbr: string; }[] Generated week + days for CalendarWeekTitle based on weekStart + +
+ +## Composition + +- Calendar uses [useBox](https://reakit.io/docs/box) +- CalendarButton uses [useButton](https://reakit.io/docs/button) +- CalendarCell uses [useBox](https://reakit.io/docs/box) +- CalendarCellButton uses [useButton](https://reakit.io/docs/button) +- CalendarGrid uses [useBox](https://reakit.io/docs/box) +- CalendarHeader uses [useBox](https://reakit.io/docs/box) +- CalendarWeekTitle uses [useBox](https://reakit.io/docs/box) + +## Example + +### Base Calendar + +```js +import React from "react"; + +import { + useCalendarState, + Calendar as CalendarWrapper, + CalendarButton, + CalendarCell, + CalendarCellButton, + CalendarGrid, + CalendarHeader, + CalendarWeekTitle, +} from "renderless-components"; + +export const App = props => { + const state = useCalendarState(props); + + return ( + +
+ + + + + + + + + + + + + +
+ + + + + {state.weekDays.map((day, dayIndex) => { + return ( + + {day.abbr} + + ); + })} + + + + {state.daysInMonth.map((week, weekIndex) => ( + + {week.map((day, dayIndex) => ( + + + + ))} + + ))} + + +
+ ); +}; + +export default App; + +const DoubleChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronRight = props => ( + +); + +const DoubleChevronRight = props => ( + +); +``` + +### Range Calendar + +```js +import React from "react"; + +import { + Calendar, + CalendarCell, + CalendarGrid, + CalendarHeader, + CalendarButton, + CalendarCellButton, + CalendarWeekTitle, + useRangeCalendarState, +} from "renderless-components"; + +export const App = props => { + const state = useRangeCalendarState(props); + + return ( + +
+ + + + + + + + + + + + + +
+ + + + + {state.weekDays.map((day, dayIndex) => { + return ( + + {day.abbr} + + ); + })} + + + + {state.daysInMonth.map((week, weekIndex) => ( + + {week.map((day, dayIndex) => ( + + + + ))} + + ))} + + +
+ ); +}; + +export default App; + +const DoubleChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronRight = props => ( + +); + +const DoubleChevronRight = props => ( + +); +``` diff --git a/docs/code-base-overview.md b/docs/code-base-overview.md new file mode 100644 index 000000000..9dceaa080 --- /dev/null +++ b/docs/code-base-overview.md @@ -0,0 +1,122 @@ +# Codebase Overview + +_Proceed if you are interested in contributing to renderless-component's +codebase_ + +Let's get a basic overview of our codebase and how our code is stuctured. + +Our codebase consists of few important folders, + +#### [/src](/src) + +This is where we keep all our components in respective subfolders. + +#### [/src/[component]/\_\_tests\_\_](/src/accordion/__tests__) + +Tests for the specific components + +#### [/src/[component]/stories](/src/accordion/stories) + +Storybook examples + +#### [/docs-templates](/docs-templates) + +Template for docs which is used for automatically generated content + +--- + +## Generated Content. + +We have code and docs generation scripts in our workflow which you should be +aware of for reducing any confusion. + +We generate: + +- keys for reakit components in [\_\_keys.ts](/src/accordion/__keys.ts) file for + each component. + + Command: `yarn keys` + +- javascript examples from Typescript examples to provide both examples in + storybook. + + Command: `yarn generatejs` + +- proptypes, composition, csb links and inject examples in the docs with special + scripts. + + Command: `yarn docsgen` + +## Docs generation guide + +For our component API documentation, we auto generate them by parsing the +typescript code and extracting information from them. + +We have [docs-templates](/docs-templates) which holds the templates for the +docs. + +See example for [accordion](/docs-templates/Accordion.md) + +### Props + +- `INJECT_PROPS` syntax will inject the prop types in its place +- Usage: `` as markdown comment. + +### Composition + +- `INJECT_COMPOSITION` will inject the composition in the specified component +- Usage: `` as markdown comment. + +### Examples + +- `IMPORT_EXAMPLE` will inject the examples from the components as code. +- Usage: `` as markdown + comment. + +### Sandbox links + +And finally Sandbox links are also dynamically generated! We can just add this +yaml as markdown comment and it will replace the comment with dynamic sandbox +link + +- `CODESANDBOX` with the links to the files will generate the csb links. +- Usage: + ```md + + ``` + +## NPM Scripts + +- `storybook` - opens storybook +- `storybook-build` - builds storybook +- `build` - bundles the library +- `test` - runs tests +- `tsd` - runs tests for typescript type check +- `keys` - generates keys for components +- `docsgen` - generates docs for components +- `generatejs` - transpiles ts examples to js +- `commit` - to commit with [gacp](https://github.com/vivaxy/gacp) +- `lint` - to lint the `src` with [ESLint](https://eslint.org/) + +## Component Docs + +- [Accordion](accordion.md) +- [Breadcrumbs](breadcrumb.md) +- [Calendar](calendar.md) +- [Date Picker](datepicker.md) +- [Drawer](drawer.md) +- [Link](Link.md) +- [Meter](meter.md) +- [Number Input](number-input.md) +- [Pagination](pagination.md) +- [Picker Base](picker-base.md) +- [Progress](progress.md) +- [Segment](segment.md) +- [Select](select.md) +- [Slider](slider.md) +- [Time Picker](timepicker.md) +- [Toast](toast.md) diff --git a/docs/core-principles.md b/docs/core-principles.md new file mode 100644 index 000000000..9df4a7793 --- /dev/null +++ b/docs/core-principles.md @@ -0,0 +1,43 @@ +# Core Principles + +Renderless components follows all the +[basic concepts from reakit](https://reakit.io/docs/basic-concepts/) to make it +more consisten overall and also composable at the same time, understanding these +concepts are essential to work with components. + +### Accessibility + +Renderless components are built with a11y in mind from the ground up by strictly +following the [WARIA 1.1 Spec](https://www.w3.org/TR/wai-aria-practices-1.1/) +and ensuring each and every component properly supports keyboard and +screen-readers. + +## Composable + +All of our components are built in a way which provides fully composability +across the board thanks to Reakit's approach to use hooks in order to built +larger components. + +## Stylable + +Components are crafted in a way that are 100% stylable with any styling +solutions available which makes them a great foundation for any Design Systems. + +## Extensible + +With composability comes extensibility, our main goal was to make the components +extensible so that even everyone can built their own Component APIs on top of +our components which enable components to be adoptable in Design Systems + +--- + +Reakit concepts which we also follow :- + +- Composition: [reakit.io/docs/composition](https://reakit.io/docs/composition) +- Accessibility: + [reakit.io/docs/accessibility](https://reakit.io/docs/accessibility) +- Styling: [reakit.io/docs/styling](https://reakit.io/docs/styling) + +

+Next | Codebase Overview โ†’ +

diff --git a/docs/datepicker.md b/docs/datepicker.md new file mode 100644 index 000000000..25218cc06 --- /dev/null +++ b/docs/datepicker.md @@ -0,0 +1,535 @@ +## DatePicker + +Accessible `DatePicker` component. + +[DatePicker - Open On Sandbox](https://codesandbox.io/s/ixpqy) + +[RangeDatePicker - Open On Sandbox](https://codesandbox.io/s/wlu79) + +## Props + + + +### `DatePicker` + +
9 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`show`** () => void Changes the `visible` state to `true` +- **`isRequired`** boolean | undefined + +- **`validationState`** "valid" | "invalid" + +
+ +### `DatePickerContent` + +
7 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`show`** () => void Changes the `visible` state to `true` + +
+ +### `DatePickerSegment` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`segment`** DateSegment + +
28 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`fieldValue`** Date + +- **`setSegment`** (part: DateTimeFormatPartTypes, v: number) => + void + +- **`increment`** (part: DateTimeFormatPartTypes) => void + +- **`decrement`** (part: DateTimeFormatPartTypes) => void + +- **`incrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`decrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`dateFormatter`** DateTimeFormat + +- **`confirmPlaceholder`** (part: DateTimeFormatPartTypes) => + void + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`isRequired`** boolean | undefined + +- **`pickerId`** string | undefined + +- **`isDateRangePicker`** boolean + +
+ +### `DatePickerSegmentField` + +
1 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. + +
+ +### `DatePickerTrigger` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
6 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`toggle`** () => void Toggles the `visible` state +- **`unstable_referenceRef`** โš ๏ธ + RefObject<HTMLElement | null> The reference element. +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +
+ +## Composition + +- DatePicker uses [usePickerBase](undefined) +- DatePickerContent uses [usePickerBaseContent](undefined) +- DatePickerSegment uses [useSegment](undefined) +- DatePickerSegmentField uses [useSegmentField](undefined) +- DatePickerTrigger uses [usePickerBaseTrigger](undefined) + +## Example + +### DatePicker + +```js +import * as React from "react"; + +import { + DatePicker, + DatePickerSegment, + DatePickerContent, + DatePickerTrigger, + useDatePickerState, + DatePickerSegmentField, + Calendar as CalendarWrapper, + CalendarButton, + CalendarCell, + CalendarCellButton, + CalendarGrid, + CalendarHeader, + CalendarWeekTitle, +} from "renderless-components"; + +export const App = props => { + const state = useDatePickerState({ + formatOptions: { month: "2-digit", day: "2-digit", year: "numeric" }, + ...props, + }); + + return ( + <> + +
+ + {state.segments.map((segment, i) => ( + + ))} + + + + + +
+
+ + + + + ); +}; + +export default App; + +const Calendar = state => { + return ( + +
+ + + + + + + + + + + + + +
+ + + + + {state.weekDays.map((day, dayIndex) => { + return ( + + {day.abbr} + + ); + })} + + + + {state.daysInMonth.map((week, weekIndex) => ( + + {week.map((day, dayIndex) => ( + + + + ))} + + ))} + + +
+ ); +}; + +const CalendarIcon = () => ( + +); + +const DoubleChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronRight = props => ( + +); + +const DoubleChevronRight = props => ( + +); +``` + +### Range Date Picker + +```js +import React from "react"; + +import { + DatePicker, + DatePickerContent, + DatePickerSegment, + DatePickerTrigger, + DatePickerSegmentField, + useDateRangePickerState, + Calendar, + CalendarCell, + CalendarGrid, + CalendarHeader, + CalendarButton, + CalendarWeekTitle, + CalendarCellButton, +} from "renderless-components"; + +export const App = props => { + const state = useDateRangePickerState({ + formatOptions: { month: "2-digit", day: "2-digit", year: "numeric" }, + ...props, + }); + + return ( + <> + +
+ + {state.startSegmentState.segments.map((segment, i) => ( + + ))} + +  -  + + {state.endSegmentState.segments.map((segment, i) => ( + + ))} + + + + +
+
+ + + + + ); +}; + +export default App; + +const RangeCalendar = state => { + return ( + +
+ + + + + + + + + + + + + +
+ + + + + {state.weekDays.map((day, dayIndex) => { + return ( + + {day.abbr} + + ); + })} + + + + {state.daysInMonth.map((week, weekIndex) => ( + + {week.map((day, dayIndex) => ( + + + + ))} + + ))} + + +
+ ); +}; + +const CalendarIcon = () => ( + +); + +const DoubleChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronLeft = props => { + return ( + + + + ); +}; + +const ChevronRight = props => ( + +); + +const DoubleChevronRight = props => ( + +); +``` diff --git a/docs/drawer.md b/docs/drawer.md new file mode 100644 index 000000000..3860ed818 --- /dev/null +++ b/docs/drawer.md @@ -0,0 +1,149 @@ +## Drawer + +Accessible `Drawer` component. + +[Drawer - Open On Sandbox](https://codesandbox.io/s/96zk3) + +## Props + + + +### `Drawer` + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`visible`** boolean Whether it's visible or not. +- **`animating`** boolean Whether it's animating or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`hide`** () => void Changes the `visible` state to `false` +- **`hideOnEsc`** boolean | undefined When enabled, user can hide + the dialog by pressing `Escape`. +- **`hideOnClickOutside`** boolean | undefined When enabled, user + can hide the dialog by clicking outside it. +- **`preventBodyScroll`** boolean | undefined When enabled, user + can't scroll on body when the dialog is visible. This option doesn't work if + the dialog isn't modal. +- **`unstable_initialFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog shows. When not set, the first tabbable element + within the dialog will be used. +- **`unstable_finalFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog hides. When not set, the disclosure component will + be used. +- **`unstable_orphan`** โš ๏ธ boolean | + undefined Whether or not the dialog should be a child of its parent. + Opening a nested orphan dialog will close its parent dialog if + `hideOnClickOutside` is set to `true` on the parent. It will be set to `false` + if `modal` is `false`. +- **`placement`** "left" | "right" | "top" | + "bottom" | undefined + +### `DrawerCloseButton` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`visible`** boolean Whether it's visible or not. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`toggle`** () => void Toggles the `visible` state + +## Composition + +- Drawer uses [useDialog](undefined) +- DrawerCloseButton uses [useDialogDisclosure](undefined) + +## Example + +```js +import React from "react"; +import { css } from "@emotion/css"; + +import { + Drawer, + useDrawerState, + DrawerBackdrop, + DrawerCloseButton, + DrawerDisclosure, +} from "renderless-components"; + +export const App = () => { + const dialog = useDrawerState({ animated: true }); + const inputRef = React.useRef(null); + const [placement, setPlacement] = React.useState("left"); + + return ( +
+ Open Drawer + + + + X +

Welcome to Reakit!

+ +
+
+
+ ); +}; + +export default App; + +const backdropStyles = css` + opacity: 0; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + transition: opacity 250ms ease-in-out; + background-color: rgba(0, 0, 0, 0.2); + &[data-enter] { + opacity: 1; + } +`; + +const cssTransforms = { + top: "translate(0, -200px)", + bottom: "translate(0, 200px)", + left: "translate(-200px, 0)", + right: "translate(200px, 0)", +}; +``` diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..860c2f99d --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,78 @@ +# Getting Started + +Collection of headless components/hooks that are accessible, composable, +customizable from low level to build your own UI & Design System powered by +[Reakit](https://reakit.io) + +## :rocket: Installation + +```sh +# npm +npm install renderless-components reakit + +# Yarn +yarn add renderless-components reakit +``` + +> Make sure `react react-dom` is installed. + +## Usage + +Code below will render an [Accordion](./Accordion.md) + +Play with this on +[CodeSandbox](https://codesandbox.io/s/renderless-accordion-seywy) + +See [Accordion](./Accordion.md) docs for more info. + +```jsx +import React from "react"; +import { + Accordion, + AccordionPanel, + AccordionTrigger, + useAccordionState, +} from "renderless-components"; + +function App() { + const state = useAccordionState(); + + return ( + +

+ Trigger 1 +

+ This is panel 1 +

+ Trigger 2 +

+ This is panel 2 +
+ ); +} + +ReactDOM.render(, document.getElementById("root")); +``` + +## Component Docs + +- [Accordion](accordion.md) +- [Breadcrumbs](breadcrumb.md) +- [Calendar](calendar.md) +- [Date Picker](datepicker.md) +- [Drawer](drawer.md) +- [Link](Link.md) +- [Meter](meter.md) +- [Number Input](number-input.md) +- [Pagination](pagination.md) +- [Picker Base](picker-base.md) +- [Progress](progress.md) +- [Segment](segment.md) +- [Select](select.md) +- [Slider](slider.md) +- [Time Picker](timepicker.md) +- [Toast](toast.md) + +

+Next | Core Principles โ†’ +

diff --git a/docs/link.md b/docs/link.md new file mode 100644 index 000000000..839668c06 --- /dev/null +++ b/docs/link.md @@ -0,0 +1,39 @@ +## Link + +Accessible `Link` component that provides the required aria role when used under +different compositions. It follows the +[WAI-ARIA Link Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#link). + +## Props + + + +### `Link` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`isExternal`** boolean | undefined Opens the link in a new tab + +## Accessibilty + +- `Link` has role `link`. + +## Composition + +- Link uses [useClickable](https://reakit.io/docs/clickable) + +## Example + +```js +import * as React from "react"; + +import { Link } from "renderless-components"; + +export const App = props => { + return Reakit; +}; + +export default App; +``` diff --git a/docs/meter.md b/docs/meter.md new file mode 100644 index 000000000..cd219ee66 --- /dev/null +++ b/docs/meter.md @@ -0,0 +1,145 @@ +## Meter + +Accessible `Meter` component. + +[Meter - Open On Sandbox](https://codesandbox.io/s/vyipe) + +## Props + + + +### `useMeterState` + +- **`value`** number The `value` of the meter indicator. + +If `undefined`/`not valid` the meter bar will be equal to `min` + +- **`min`** number The minimum value of the meter +- **`max`** number The maximum value of the meter +- **`low`** number The higher limit of min range. + +Defaults to `min`. + +- **`optimum`** number The lower limit of max range. + +Defaults to `median of low & high`. + +- **`high`** number The lower limit of max range. + +Defaults to `max`. + +### `Meter` + +
4 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`value`** number The `value` of the meter indicator. + +If `undefined`/`not valid` the meter bar will be equal to `min` + +- **`min`** number The minimum value of the meter +- **`max`** number The maximum value of the meter +- **`percent`** number Percentage of the value progressed with + respect to min & max + +
+ +## Composition + +- Meter uses [useBox](https://reakit.io/docs/box) + +## Example + +```js +import * as React from "react"; +import { css, keyframes } from "@emotion/css"; + +import { Meter, useMeterState } from "renderless-components"; + +export const App = props => { + const { + children, + withLabel = false, + withStripe = false, + withStripeAnimation = false, + ...rest + } = props; + const meter = useMeterState(rest); + + return ( +
+ + {withLabel &&
{`${meter.percent}%`}
} +
+ ); +}; + +export default App; + +const meterStyle = css({ + position: "relative", + width: "500px", + height: "1rem", + background: "whiteSmoke", + borderRadius: "3px", + border: "1px solid #ccc", + boxShadow: "0 5px 5px -5px #333 inset", + overflow: "hidden", +}); + +const labelStyles = css({ + top: "50%", + left: "50%", + width: "100%", + textAlign: "center", + position: "absolute", + transform: "translate(-50%, -50%)", + fontWeight: "bold", + fontSize: "0.75em", + lineHeight: 1, +}); + +const stripeAnim = keyframes({ + from: { backgroundPosition: "1rem 0" }, + to: { backgroundPosition: "0 0" }, +}); + +const background = { + safe: "#8bcf69", + caution: "#e6d450", + danger: "#f28f68", +}; + +const generateStripe = { + backgroundImage: `linear-gradient( + 45deg, + rgba(255, 255, 255, 0.15) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.15) 50%, + rgba(255, 255, 255, 0.15) 75%, + transparent 75%, + transparent +)`, + backgroundSize: "1rem 1rem", +}; + +function meterBarStyle(meter, props) { + const { percent, status } = meter; + const { withStripe, withStripeAnimation } = props; + + return css({ + backgroundColor: status == null ? undefined : background[status], + width: percent != null ? `${percent}%` : 0, + height: "100%", + ...(withStripe && { ...generateStripe }), + ...(withStripe && + withStripeAnimation && { animation: `${stripeAnim} 1s linear infinite` }), + }); +} +``` diff --git a/docs/number-input.md b/docs/number-input.md new file mode 100644 index 000000000..9aac8840d --- /dev/null +++ b/docs/number-input.md @@ -0,0 +1,180 @@ +## NumberInput + +Accessible `NumberInput` component. + +[NumberInput - Open On Sandbox](https://codesandbox.io/s/siflz) + +## Props + + + +### `useNumberinputState` + +- **`value`** string | number The value of the counter. Should be + less than `max` and greater than `min` + +If no value, initial value is set to `""` + +- **`keepWithinRange`** boolean This controls the value update + behavior in general. + +- If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + +- If `false`, the value will be allowed to go out of range. +- **`min`** number The minimum value of the counter +- **`max`** number The maximum value of the counter +- **`step`** number The step used to increment or decrement the + value +- **`precision`** number The number of decimal points used to round + the value + +If no precision, initial value is from the decimal places from value/step - `0` + +- **`defaultValue`** string | number | undefined The initial value + of the counter. Should be less than `max` and greater than `min` +- **`onChange`** + ((valueAsString: + string, valueAsNumber: number)... The callback fired when the value + changes +- **`focusInputOnChange`** boolean | undefined If `true`, the input + will be focused as you increment or decrement the value with the stepper + +### `NumberInput` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`clampValueOnBlur`** boolean | undefined This controls the + value update when you blur out of the input. +- If `true` and the value is greater than `max`, the value will be reset to + `max` +- Else, the value remains the same. +- **`allowMouseWheel`** boolean | undefined If `true`, the input's +value will change based on mouse wheel +
12 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`keepWithinRange`** boolean This controls the value update + behavior in general. + +- If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + +- If `false`, the value will be allowed to go out of range. +- **`value`** string | number The value of the counter. Should be + less than `max` and greater than `min` + +If no value, initial value is set to `""` + +- **`min`** number The minimum value of the counter +- **`max`** number The maximum value of the counter +- **`step`** number The step used to increment or decrement the + value +- **`valueAsNumber`** number The value of the counter in number. +- **`isOutOfRange`** boolean True, if value is less than `min` & + greater than `max`. +- **`inputRef`** RefObject<HTMLElement | null> The Input + Element. +- **`setValue`** (next: StringOrNumber) => void Set the value + which will be converted to string. +- **`increment`** (step: number) => void Increment the value + based on the step +- **`decrement`** (step: number) => void Decrement the value + based on the step +- **`setCastedValue`** (value: StringOrNumber) => void Set the + casted value based on precision & step. + +
+ +### `NumberInputDecrementButton` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
5 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`keepWithinRange`** boolean This controls the value update + behavior in general. + +- If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + +- If `false`, the value will be allowed to go out of range. +- **`isAtMin`** boolean Truw, if value is equal to min. +- **`focusInput`** () => void Focus input if focus input on + value change is `true` +- **`spinDown`** () => void Spinner handler that decrements the + value after an interval +- **`spinStop`** () => void Spinner handler that Stop it from + incrementing or decrementing + +
+ +### `NumberInputIncrementButton` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
5 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`keepWithinRange`** boolean This controls the value update + behavior in general. + +- If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + +- If `false`, the value will be allowed to go out of range. +- **`isAtMax`** boolean True, if value is equal to max. +- **`focusInput`** () => void Focus input if focus input on + value change is `true` +- **`spinUp`** () => void Spinner handler that increments the + value after an interval +- **`spinStop`** () => void Spinner handler that Stop it from + incrementing or decrementing + +
+ +## Composition + +- NumberInput uses [useInput](undefined) +- NumberInputDecrementButton uses [useButton](https://reakit.io/docs/button) +- NumberInputIncrementButton uses [useButton](https://reakit.io/docs/button) + +## Example + +```js +import * as React from "react"; + +import { + NumberInput, + useNumberInputState, + NumberInputDecrementButton, + NumberInputIncrementButton, +} from "renderless-components"; + +export const App = props => { + const state = useNumberInputState(props); + const { clampValueOnBlur, allowMouseWheel } = props; + + return ( + + ); +}; + +export default App; +``` diff --git a/docs/pagination.md b/docs/pagination.md new file mode 100644 index 000000000..b6680583e --- /dev/null +++ b/docs/pagination.md @@ -0,0 +1,139 @@ +## Pagination + +Accessible `Pagination` component. + +[Pagination - Open On Sandbox](https://codesandbox.io/s/ugo4e) + +## Props + + + +### `usePaginationState` + +- **`defaultPage`** number | undefined Set the default + page(uncontrollable) +- **`page`** number | undefined Set the page(controllable) +- **`onChange`** ((page: number) => void) | undefined + +- **`count`** number | undefined Total no. of pages +- **`boundaryCount`** number | undefined No. of boundary pages to + be visible +- **`siblingCount`** number | undefined No. of sibiling pages + allowed before/after the current page + +### `Pagination` + +
9 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`currentPage`** number The current active page +- **`pages`** (string | number)[] All the page with start & end + ellipsis +- **`isAtFirstPage`** boolean True, if the currentPage is at first + page +- **`isAtLastPage`** boolean True, if the currentPage is at last + page +- **`movePage`** (page: number) => void Go to the specified + page number +- **`nextPage`** () => void Go to next page +- **`prevPage`** () => void Go to previous page +- **`firstPage`** () => void Go to first page +- **`lastPage`** () => void Go to last page + +
+ +### `PaginationButton` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`goto`** + number + | "nextPage" | "prevPage" | "firstPage" ... + +
8 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`currentPage`** number The current active page +- **`movePage`** (page: number) => void Go to the specified + page number +- **`nextPage`** () => void Go to next page +- **`prevPage`** () => void Go to previous page +- **`firstPage`** () => void Go to first page +- **`lastPage`** () => void Go to last page +- **`isAtLastPage`** boolean True, if the currentPage is at last + page +- **`isAtFirstPage`** boolean True, if the currentPage is at first + page + +
+ +## Composition + +- Pagination uses [useBox](https://reakit.io/docs/box) +- PaginationButton uses [useButton](https://reakit.io/docs/button) + +## Example + +```js +import * as React from "react"; + +import { + Pagination, + PaginationButton, + usePaginationState, +} from "renderless-components"; + +export const App = props => { + const state = usePaginationState({ count: 10, ...props }); + + return ( + +
    +
  • + + First + +
  • +
  • + + Previous + +
  • + {state.pages.map(page => { + if (page === "start-ellipsis" || page === "end-ellipsis") { + return
  • ...
  • ; + } + + return ( +
  • + + {page} + +
  • + ); + })} +
  • + + Next + +
  • +
  • + + Last + +
  • +
+
+ ); +}; + +export default App; +``` diff --git a/docs/picker-base.md b/docs/picker-base.md new file mode 100644 index 000000000..fa5773fd9 --- /dev/null +++ b/docs/picker-base.md @@ -0,0 +1,129 @@ +## PickerBase + +Accessible `PickerBase` component. + +[PickerBase - Open On Sandbox](https://codesandbox.io/s/neryg) + +## Props + + + +### `PickerBase` + +
7 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`show`** () => void Changes the `visible` state to `true` + +
+ +### `PickerBaseContent` + +- **`hideOnEsc`** boolean | undefined When enabled, user can hide + the dialog by pressing `Escape`. +- **`hideOnClickOutside`** boolean | undefined When enabled, user + can hide the dialog by clicking outside it. +- **`preventBodyScroll`** boolean | undefined When enabled, user + can't scroll on body when the dialog is visible. This option doesn't work if + the dialog isn't modal. +- **`unstable_initialFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog shows. When not set, the first tabbable element + within the dialog will be used. +- **`unstable_finalFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog hides. When not set, the disclosure component will + be used. +- **`unstable_orphan`** โš ๏ธ boolean | +undefined Whether or not the dialog should be a child of its parent. +Opening a nested orphan dialog will close its parent dialog if +`hideOnClickOutside` is set to `true` on the parent. It will be set to `false` +if `modal` is `false`. +
8 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`visible`** boolean Whether it's visible or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`hide`** () => void Changes the `visible` state to `false` +- **`dialogId`** string | undefined + +
+ +### `PickerBaseTrigger` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
6 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`toggle`** () => void Toggles the `visible` state +- **`unstable_referenceRef`** โš ๏ธ + RefObject<HTMLElement | null> The reference element. +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +
+ +## Composition + +- PickerBase uses [useBox](https://reakit.io/docs/box) +- PickerBaseContent uses [usePopover](undefined) +- PickerBaseTrigger uses [usePopoverDisclosure](undefined) + +## Example + +```js +import * as React from "react"; + +import { + PickerBase, + PickerBaseTrigger, + PickerBaseContent, + usePickerBaseState, +} from "renderless-components"; + +export const App = props => { + const state = usePickerBaseState(props); + + return ( + <> + + open + + Content + + ); +}; + +export default App; +``` diff --git a/docs/progress.md b/docs/progress.md new file mode 100644 index 000000000..92b5be9e7 --- /dev/null +++ b/docs/progress.md @@ -0,0 +1,174 @@ +## Progress + +Accessible `Progress` component. + +[Progress - Open On Sandbox](https://codesandbox.io/s/42dwp) + +## Props + + + +### `useProgressState` + +- **`value`** number | null The `value` of the progress indicator. + +If `null` the progress bar will be in `indeterminate` state + +- **`min`** number The minimum value of the progress +- **`max`** number The maximum value of the + +### `Progress` + +
4 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`value`** number | null The `value` of the progress indicator. + +If `null` the progress bar will be in `indeterminate` state + +- **`min`** number The minimum value of the progress +- **`max`** number The maximum value of the +- **`isIndeterminate`** boolean Set isInterminate state + +
+ +## Composition + +- Progress uses [useBox](https://reakit.io/docs/box) + +## Example + +```js +import * as React from "react"; +import { Button } from "reakit"; +import { css, keyframes } from "@emotion/css"; + +import { cx, isNull, Progress, useProgressState } from "renderless-components"; + +export const App = props => { + const { + children, + withLabel = false, + withStripe = false, + withStripeAnimation = false, + ...rest + } = props; + const state = useProgressState(rest); + const { value, setValue, percent, isIndeterminate } = state; + + React.useEffect(() => { + const clearId = setInterval(() => { + !isIndeterminate && + setValue(prevValue => { + if (isNull(prevValue)) return prevValue; + return prevValue + 5; + }); + }, 500); + + if (value === 100) { + clearInterval(clearId); + } + + return () => { + clearInterval(clearId); + }; + }, [setValue, isIndeterminate, value]); + + return ( +
+
+ {withLabel ?
{`${percent}%`}
: null} + +
+
+ +
+ ); +}; + +export default App; + +const progressStyle = css({ + background: "rgb(237, 242, 247)", + height: "0.5rem", + width: "400px", + overflow: "hidden", + position: "relative", +}); + +const progressBarStyle = percent => { + return css({ + transition: "all 0.3s", + backgroundColor: "#3182ce", + width: `${percent}%`, + height: "100%", + }); +}; + +export const labelStyles = css({ + top: "50%", + left: "50%", + width: "100%", + textAlign: "center", + position: "absolute", + transform: "translate(-50%, -50%)", + fontWeight: "bold", + fontSize: "0.75em", + lineHeight: 1, +}); + +function generateStripe(size = "1rem", color = "rgba(255, 255, 255, 0.15)") { + return css({ + backgroundImage: `linear-gradient( + 45deg, + ${color} 25%, + transparent 25%, + transparent 50%, + ${color} 50%, + ${color} 75%, + transparent 75%, + transparent + )`, + backgroundSize: `${size} ${size}`, + }); +} + +const stripStyles = generateStripe(); + +const stripe = keyframes({ + from: { backgroundPosition: "1rem 0" }, + to: { backgroundPosition: "0 0" }, +}); + +const stripAnim = css({ + animation: `${stripe} 1s linear infinite`, +}); + +const progressAnim = keyframes({ + "0%": { left: "-40%" }, + "100%": { left: "100%" }, +}); + +const indeterminateStyles = css({ + position: "absolute", + willChange: "left", + minWidth: "50%", + width: "100%", + height: "100%", + backgroundImage: + "linear-gradient( to right, transparent 0%, #3182ce 50%, transparent 100% )", + animation: `${progressAnim} 1s ease infinite normal none running`, +}); +``` diff --git a/docs/segment.md b/docs/segment.md new file mode 100644 index 000000000..c3d1b2f55 --- /dev/null +++ b/docs/segment.md @@ -0,0 +1,200 @@ +## Segment + +Accessible `Segment` component. + +[Segment - Open On Sandbox](https://codesandbox.io/s/xiccb) + +## Props + + + +### `Segment` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`segment`** DateSegment + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`isRequired`** boolean | undefined + +
23 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`fieldValue`** Date + +- **`setSegment`** (part: DateTimeFormatPartTypes, v: number) => + void + +- **`increment`** (part: DateTimeFormatPartTypes) => void + +- **`decrement`** (part: DateTimeFormatPartTypes) => void + +- **`incrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`decrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`dateFormatter`** DateTimeFormat + +- **`confirmPlaceholder`** (part: DateTimeFormatPartTypes) => + void + +
+ +### `SegmentField` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
12 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. + +
+ +## Composition + +- Segment uses [useCompositeItem](https://reakit.io/docs/composite) +- SegmentField uses [useComposite](https://reakit.io/docs/composite) + +## Example + +```js +import React from "react"; + +import { Segment, SegmentField, useSegmentState } from "renderless-components"; + +export const App = props => { + const state = useSegmentState(props); + + return ( +
+ + {state.segments.map((segment, i) => ( + + ))} + +
+ ); +}; + +export default App; +``` diff --git a/docs/select.md b/docs/select.md new file mode 100644 index 000000000..70e361fb6 --- /dev/null +++ b/docs/select.md @@ -0,0 +1,755 @@ +## Select + +Accessible `Select` component. + +[Select - Open On Sandbox](https://codesandbox.io/s/tcnxl) + +## Props + + + +### `useSelectBaseState` + +- **`values`** string[] Options/values provided. +- **`selectedValue`** string | null Initial value to be selected + +### `useSelectListState` + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. +- **`values`** string[] Options/values provided. +- **`selectedValue`** string | null Initial value to be selected + +### `useSelectPopoverState` + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`visible`** boolean Whether it's visible or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`placement`** + "auto-start" + | "auto" | "auto-end" | "top-start... Actual + `placement`. +- **`unstable_fixed`** โš ๏ธ boolean | + undefined Whether or not the popover should have `position` set to + `fixed`. +- **`unstable_flip`** โš ๏ธ boolean | + undefined Flip the popover's placement when it starts to overlap its + reference element. +- **`unstable_offset`** โš ๏ธ [string | + number, string | number] | undefined Offset between the reference and + the popover: [main axis, alt axis]. Should not be combined with `gutter`. +- **`gutter`** number | undefined Offset between the reference and + the popover on the main axis. Should not be combined with `unstable_offset`. +- **`unstable_preventOverflow`** โš ๏ธ + boolean | undefined Prevents popover from being positioned + outside the boundary. + +### `useSelectState` + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`visible`** boolean Whether it's visible or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`placement`** + "auto-start" + | "auto" | "auto-end" | "top-start... Actual + `placement`. +- **`unstable_fixed`** โš ๏ธ boolean | + undefined Whether or not the popover should have `position` set to + `fixed`. +- **`unstable_flip`** โš ๏ธ boolean | + undefined Flip the popover's placement when it starts to overlap its + reference element. +- **`unstable_offset`** โš ๏ธ [string | + number, string | number] | undefined Offset between the reference and + the popover: [main axis, alt axis]. Should not be combined with `gutter`. +- **`gutter`** number | undefined Offset between the reference and + the popover on the main axis. Should not be combined with `unstable_offset`. +- **`unstable_preventOverflow`** โš ๏ธ + boolean | undefined Prevents popover from being positioned + outside the boundary. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. +- **`values`** string[] Options/values provided. +- **`selectedValue`** string | null Initial value to be selected + +### `Select` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`hideOnEsc`** boolean | undefined When enabled, user can hide +the select popover by pressing `esc` while focusing on the select input. +
53 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`toggle`** () => void Toggles the `visible` state +- **`unstable_referenceRef`** โš ๏ธ + RefObject<HTMLElement | null> The reference element. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`placement`** + "auto-start" + | "auto" | "auto-end" | "top-start... Actual + `placement`. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`menuRole`** "listbox" | "tree" | "grid" | + "dialog" Indicates the type of the suggestions popup. +- **`items`** Item[] Lists all the select items with their `id`, + DOM `ref`, `disabled` state, `value` and `groupId` if any. This state is + automatically updated when `registerItem` and `unregisterItem` are called. +- **`values`** string[] Options/values provided. +- **`valuesById`** { id: string; value: string; }[] Initial value + to be selected +- **`selectedValue`** string | null Initial value to be selected +- **`currentValue`** string | undefined Initial value to be + selected +- **`selectedId`** string | null | undefined Id of the item that is + currently selected. +- **`setBaseId`** (value: SetStateAction<string>) => + void Sets `baseId`. +- **`show`** () => void Changes the `visible` state to `true` +- **`hide`** () => void Changes the `visible` state to `false` +- **`setVisible`** (value: SetStateAction<boolean>) => + void Sets `visible`. +- **`setAnimated`** (value: SetStateAction<number | boolean>) + => void Sets `animated`. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`setModal`** (value: SetStateAction<boolean>) => + void Sets `modal`. +- **`place`** (value: SetStateAction<Placement>) => + void Change the `placement` state. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`registerGroup`** (group: Group) => void Registers a + composite group. +- **`unregisterGroup`** (id: string) => void Unregisters a + composite group. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`sort`** () => void Sorts the `composite.items` based on + the items position in the DOM. This is especially useful after modifying the + composite items order in the DOM. Most of the time, though, you don't need to + manually call this function as the re-ordering happens automatically. +- **`unstable_setVirtual`** โš ๏ธ (value: + SetStateAction<boolean>) => void Sets `virtual`. +- **`setRTL`** (value: SetStateAction<boolean>) => void + Sets `rtl`. +- **`setOrientation`** + (value: + SetStateAction<"horizontal" | "vertical... Sets + `orientation`. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`setLoop`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `loop`. +- **`setWrap`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `wrap`. +- **`setShift`** (value: SetStateAction<boolean>) => + void Sets `shift`. +- **`reset`** () => void Resets to initial state. +- **`registerItem`** (item: Item) => void Registers a select + item. +- **`setSelectedValue`** (value: SetStateAction<string | null>) + => void Sets `values`. + +
+ +### `SelectItem` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`value`** string | undefined Item's value that will be used to +fill input value and filter `matches` based on the input value. You can omit +this for items that perform actions other than filling a form. For example, +items may open a dialog. +
18 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`visible`** boolean Whether it's visible or not. +- **`hide`** () => void Changes the `visible` state to `false` +- **`setSelectedValue`** (value: SetStateAction<string | null>) + => void Sets `values`. + +
+ +### `SelectList` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
13 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`menuRole`** "listbox" | "tree" | "grid" | + "dialog" Indicates the type of the suggestions popup. + +
+ +### `SelectOption` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`value`** string | undefined Item's value that will be used to +fill input value and filter `matches` based on the input value. You can omit +this for items that perform actions other than filling a form. For example, +items may open a dialog. +
18 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`visible`** boolean Whether it's visible or not. +- **`hide`** () => void Changes the `visible` state to `false` +- **`setSelectedValue`** (value: SetStateAction<string | null>) + => void Sets `values`. + +
+ +### `SelectPopover` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`hideOnEsc`** boolean | undefined When enabled, user can hide + the dialog by pressing `Escape`. +- **`hideOnClickOutside`** boolean | undefined When enabled, user + can hide the dialog by clicking outside it. +- **`preventBodyScroll`** boolean | undefined When enabled, user + can't scroll on body when the dialog is visible. This option doesn't work if + the dialog isn't modal. +- **`unstable_initialFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog shows. When not set, the first tabbable element + within the dialog will be used. +- **`unstable_finalFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog hides. When not set, the disclosure component will + be used. +- **`unstable_orphan`** โš ๏ธ boolean | +undefined Whether or not the dialog should be a child of its parent. +Opening a nested orphan dialog will close its parent dialog if +`hideOnClickOutside` is set to `true` on the parent. It will be set to `false` +if `modal` is `false`. +
22 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`menuRole`** "listbox" | "tree" | "grid" | + "dialog" Indicates the type of the suggestions popup. +- **`visible`** boolean Whether it's visible or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`hide`** () => void Changes the `visible` state to `false` +- **`values`** string[] Options/values provided. +- **`valuesById`** { id: string; value: string; }[] Initial value + to be selected +- **`currentValue`** string | undefined Initial value to be + selected + +
+ +## Composition + +- Select uses [usePopoverDisclosure](undefined) +- SelectItem uses [useCompositeItem](https://reakit.io/docs/composite) +- SelectList uses [useComposite](https://reakit.io/docs/composite) +- SelectOption uses [useSelectItem](undefined) +- SelectPopover uses [useSelectList](undefined) and [usePopover](undefined) + +## Example + +```js +import * as React from "react"; + +import { + Select, + SelectOption, + SelectPopover, + useSelectState, +} from "renderless-components"; + +export const App = props => { + const select = useSelectState({ gutter: 8, ...props }); + + return ( + <> + + + + + + + + + ); +}; + +export default App; +``` diff --git a/docs/slider.md b/docs/slider.md new file mode 100644 index 000000000..4604fae88 --- /dev/null +++ b/docs/slider.md @@ -0,0 +1,273 @@ +## Slider + +Accessible `Slider` component. + +[Slider - Open On Sandbox](https://codesandbox.io/s/d0mp9) + +## Props + + + +### `useSliderState` + +- **`values`** number[] The `value` of the slider indicator. + +If `undefined`/`not valid` the slider bar will be the optimum of min & max + +- **`min`** number The minimum value of the slider +- **`max`** number The maximum value of the slider +- **`step`** number The step in which increments/decrements have to + be made +- **`isDisabled`** boolean If `true`, the slider will be disabled +- **`orientation`** "horizontal" | "vertical" + Orientation of the slider +- **`reversed`** boolean Direction of the slider +- **`defaultValues`** number[] | undefined The `defaultValue` of + the slider indicator. +- **`onChange`** ((value: number[]) => void) | undefined + Handler that is called when the value changes. +- **`onChangeEnd`** ((value: number[]) => void) | undefined Get + the value when dragging is started +- **`onChangeStart`** ((value: number[]) => void) | undefined + Get the value when dragging is stopped +- **`formatOptions`** NumberFormatOptions | undefined Get the + formated value based on number format options + +### `SliderInput` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`id`** string | undefined Same as the HTML attribute. +- **`index`** number + +
10 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`step`** number The step in which increments/decrements have to + be made +- **`isDisabled`** boolean If `true`, the slider will be disabled +- **`orientation`** "horizontal" | "vertical" + Orientation of the slider +- **`getThumbMinValue`** (index: number) => number Returns the + min values for the index +- **`getThumbMaxValue`** (index: number) => number Returns the + max values for the index +- **`getThumbValueLabel`** (index: number) => string Returns + the formatted thumb value based on it's index +- **`registerInput`** (item: Item) => void Register the inputs + on mount +- **`unregisterInput`** (id: string) => void Unregister the + inputs on mount +- **`setFocusedThumb`** (index: number | undefined) => void Set + currently Focused Thumb +- **`setThumbValue`** (index: number, value: number) => void + Sets value for thumb. The actually value set will be clamped and rounded + according to min/max/step + +
+ +### `SliderThumb` + +- **`index`** number + +
13 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`step`** number The step in which increments/decrements have to + be made +- **`isDisabled`** boolean If `true`, the slider will be disabled +- **`orientation`** "horizontal" | "vertical" + Orientation of the slider +- **`reversed`** boolean Direction of the slider +- **`trackRef`** RefObject<HTMLElement | null> The track + slider element. +- **`focusedThumb`** number | undefined Currently focused thumb +- **`getThumbValue`** (index: number) => number Get Thumb value + based on its index +- **`getThumbPercent`** (index: number) => number Returns the + value offset as a percentage from 0 to 1. +- **`inputs`** Item[] Get all the inputs in the DOM +- **`setThumbValue`** (index: number, value: number) => void + Sets value for thumb. The actually value set will be clamped and rounded + according to min/max/step +- **`setThumbEditable`** (index: number, editable: boolean) => + void Set true if the thumb registered is editable +- **`setThumbDragging`** (index: number, dragging: boolean) => + void set dragging true if the thumb registered is being currently + dragged +- **`setThumbPercent`** (index: number, percent: number) => + void Sets value for thumb by percent offset (between 0 and 1) + +
+ +### `SliderTrack` + +
13 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`values`** number[] The `value` of the slider indicator. + +If `undefined`/`not valid` the slider bar will be the optimum of min & max + +- **`isDisabled`** boolean If `true`, the slider will be disabled +- **`orientation`** "horizontal" | "vertical" + Orientation of the slider +- **`reversed`** boolean Direction of the slider +- **`trackRef`** RefObject<HTMLElement | null> The track + slider element. +- **`getThumbPercent`** (index: number) => number Returns the + value offset as a percentage from 0 to 1. +- **`getPercentValue`** (percent: number) => number Converts a + percent along track (between 0 and 1) to the corresponding value +- **`isThumbEditable`** (index: number) => boolean Get + editableThumb based on the index +- **`isThumbDragging`** (index: number) => boolean Whether a + specific index is being dragged +- **`setFocusedThumb`** (index: number | undefined) => void Set + currently Focused Thumb +- **`setThumbValue`** (index: number, value: number) => void + Sets value for thumb. The actually value set will be clamped and rounded + according to min/max/step +- **`setThumbDragging`** (index: number, dragging: boolean) => + void set dragging true if the thumb registered is being currently + dragged +- **`setThumbPercent`** (index: number, percent: number) => + void Sets value for thumb by percent offset (between 0 and 1) + +
+ +## Composition + +- SliderInput uses [unstable_useId](https://reakit.io/docs/id) and + [useInput](undefined) +- SliderThumb uses [useBox](https://reakit.io/docs/box) +- SliderTrack uses [useBox](https://reakit.io/docs/box) + +## Example + +```js +import * as React from "react"; +import { VisuallyHidden } from "reakit"; + +import { + SliderTrack, + SliderThumb, + SliderInput, + useSliderState, +} from "renderless-components"; + +export const App = args => { + const { label, isReversed, origin: originProp, ...rest } = args; + const origin = originProp ?? args.min ?? 0; + + const state = useSliderState({ reversed: isReversed, ...rest }); + const { + values, + getValuePercent, + getThumbValueLabel, + getThumbPercent, + } = state; + + const isVertical = args.orientation === "vertical"; + const isRange = values.length === 2; + const isMulti = values.length > 2; + + const labelValue = !isRange + ? getThumbValueLabel(0) + : `${state.getThumbValueLabel(0)} to ${state.getThumbValueLabel(1)}`; + const trackWidth = !isRange + ? `${ + (getValuePercent(Math.max(values[0], origin)) - + getValuePercent(Math.min(values[0], origin))) * + 100 + }%` + : `${(state.getThumbPercent(1) - state.getThumbPercent(0)) * 100}%`; + const trackLeft = !isRange + ? `${getValuePercent(Math.min(values[0], origin)) * 100}%` + : `${getThumbPercent(0) * 100}%`; + const trackRight = !isRange ? "0px" : `${getThumbPercent(0) * 100}%`; + + return ( +
+
+ +
+ {!isMulti ? labelValue : JSON.stringify(state.values)} +
+
+ +
+ +
+ {!isMulti ? ( +
+ ) : null} + + + {[...new Array(values.length).keys()].map(index => { + return ( +
+ + + + + + {args.showTip && ( +
+ {getThumbValueLabel(index)} +
+ )} +
+ ); + })} +
+
+ ); +}; + +export default App; +``` diff --git a/docs/timepicker.md b/docs/timepicker.md new file mode 100644 index 000000000..49f78b344 --- /dev/null +++ b/docs/timepicker.md @@ -0,0 +1,832 @@ +## TimePicker + +Accessible `TimePicker` component. + +[TimePicker - Open On Sandbox](https://codesandbox.io/s/mdhu9) + +## Props + + + +### `TimePicker` + +
7 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`show`** () => void Changes the `visible` state to `true` + +
+ +### `TimePickerColumn` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
13 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`columnType`** "hour" | "minute" | + "meridian" + +
+ +### `TimePickerColumnValue` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`value`** number + +
19 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`visible`** boolean | undefined + +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`selected`** number + +- **`setSelected`** (value: number) => void + +
+ +### `TimePickerContent` + +- **`hideOnEsc`** boolean | undefined When enabled, user can hide + the dialog by pressing `Escape`. +- **`hideOnClickOutside`** boolean | undefined When enabled, user + can hide the dialog by clicking outside it. +- **`preventBodyScroll`** boolean | undefined When enabled, user + can't scroll on body when the dialog is visible. This option doesn't work if + the dialog isn't modal. +- **`unstable_initialFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog shows. When not set, the first tabbable element + within the dialog will be used. +- **`unstable_finalFocusRef`** โš ๏ธ + RefObject<HTMLElement> | undefined The element that will + be focused when the dialog hides. When not set, the disclosure component will + be used. +- **`unstable_orphan`** โš ๏ธ boolean | +undefined Whether or not the dialog should be a child of its parent. +Opening a nested orphan dialog will close its parent dialog if +`hideOnClickOutside` is set to `true` on the parent. It will be set to `false` +if `modal` is `false`. +
8 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`hide`** () => void Changes the `visible` state to `false` +- **`dialogId`** string | undefined + +
+ +### `TimePickerSegment` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is + `disabled`, it may still be `focusable`. It works similarly to `readOnly` on + form elements. In this case, only `aria-disabled` will be set. +- **`id`** string | undefined Same as the HTML attribute. +- **`segment`** DateSegment + +- **`isRequired`** boolean | undefined + +
68 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`fieldValue`** Date + +- **`setSegment`** (part: DateTimeFormatPartTypes, v: number) => + void + +- **`increment`** (part: DateTimeFormatPartTypes) => void + +- **`decrement`** (part: DateTimeFormatPartTypes) => void + +- **`incrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`decrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`dateFormatter`** DateTimeFormat + +- **`confirmPlaceholder`** (part: DateTimeFormatPartTypes) => + void + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`setFieldValue`** (value: Date) => void + +- **`segments`** DateSegment[] + +- **`setBaseId`** (value: SetStateAction<string>) => + void Sets `baseId`. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. +- **`registerGroup`** (group: Group) => void Registers a + composite group. +- **`unregisterGroup`** (id: string) => void Unregisters a + composite group. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`sort`** () => void Sorts the `composite.items` based on + the items position in the DOM. This is especially useful after modifying the + composite items order in the DOM. Most of the time, though, you don't need to + manually call this function as the re-ordering happens automatically. +- **`unstable_setVirtual`** โš ๏ธ (value: + SetStateAction<boolean>) => void Sets `virtual`. +- **`setRTL`** (value: SetStateAction<boolean>) => void + Sets `rtl`. +- **`setOrientation`** + (value: + SetStateAction<"horizontal" | "vertical... Sets + `orientation`. +- **`setLoop`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `loop`. +- **`setWrap`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `wrap`. +- **`setShift`** (value: SetStateAction<boolean>) => + void Sets `shift`. +- **`reset`** () => void Resets to initial state. +- **`visible`** boolean Whether it's visible or not. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`show`** () => void Changes the `visible` state to `true` +- **`hide`** () => void Changes the `visible` state to `false` +- **`toggle`** () => void Toggles the `visible` state +- **`setVisible`** (value: SetStateAction<boolean>) => + void Sets `visible`. +- **`setAnimated`** (value: SetStateAction<number | boolean>) + => void Sets `animated`. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`setModal`** (value: SetStateAction<boolean>) => + void Sets `modal`. +- **`unstable_referenceRef`** โš ๏ธ + RefObject<HTMLElement | null> The reference element. +- **`placement`** + "auto-start" + | "auto" | "auto-end" | "top-start... Actual + `placement`. +- **`place`** (value: SetStateAction<Placement>) => + void Change the `placement` state. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`time`** Date + +- **`hours`** number[] + +- **`minutes`** number[] + +- **`meridies`** string[] + +- **`hourState`** + { + baseId: string; unstable_idCountRef: MutableR... + +- **`minuteState`** + { + baseId: string; unstable_idCountRef: MutableR... + +- **`meridiesState`** + { + baseId: string; unstable_idCountRef: MutableR... + +
+ +### `TimePickerSegmentField` + +- **`disabled`** boolean | undefined Same as the HTML attribute. +- **`focusable`** boolean | undefined When an element is +`disabled`, it may still be `focusable`. It works similarly to `readOnly` on +form elements. In this case, only `aria-disabled` will be set. +
12 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. + +
+ +### `TimePickerTrigger` + +
68 state props +> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic. + +- **`visible`** boolean Whether it's visible or not. +- **`pickerId`** string | undefined + +- **`dialogId`** string | undefined + +- **`isDisabled`** boolean | undefined + +- **`isReadOnly`** boolean | undefined + +- **`segmentFocus`** (() => void) | undefined + +- **`show`** () => void Changes the `visible` state to `true` +- **`fieldValue`** Date + +- **`setFieldValue`** (value: Date) => void + +- **`segments`** DateSegment[] + +- **`dateFormatter`** DateTimeFormat + +- **`increment`** (part: DateTimeFormatPartTypes) => void + +- **`decrement`** (part: DateTimeFormatPartTypes) => void + +- **`incrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`decrementPage`** (part: DateTimeFormatPartTypes) => void + +- **`setSegment`** (part: DateTimeFormatPartTypes, v: number) => + void + +- **`confirmPlaceholder`** (part: DateTimeFormatPartTypes) => + void + +- **`baseId`** string ID that will serve as a base for all the + items IDs. +- **`setBaseId`** (value: SetStateAction<string>) => + void Sets `baseId`. +- **`unstable_virtual`** โš ๏ธ + boolean If enabled, the composite element will act as an + [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) + container instead of + [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). + DOM focus will remain on the composite while its items receive virtual focus. +- **`rtl`** boolean Determines how `next` and `previous` functions + will behave. If `rtl` is set to `true`, they will be inverted. This only + affects the composite widget behavior. You still need to set `dir="rtl"` on + HTML/CSS. +- **`orientation`** "horizontal" | "vertical" | + undefined Defines the orientation of the composite widget. If the + composite has a single row or column (one-dimensional), the `orientation` + value determines which arrow keys can be used to move focus: + + - `undefined`: all arrow keys work. + - `horizontal`: only left and right arrow keys work. + - `vertical`: only up and down arrow keys work. + + It doesn't have any effect on two-dimensional composites. + +- **`items`** Item[] Lists all the composite items with their `id`, + DOM `ref`, `disabled` state and `groupId` if any. This state is automatically + updated when `registerItem` and `unregisterItem` are called. +- **`groups`** Group[] Lists all the composite groups with their + `id` and DOM `ref`. This state is automatically updated when `registerGroup` + and `unregisterGroup` are called. +- **`currentId`** string | null | undefined The current focused + item `id`. + - `undefined` will automatically focus the first enabled composite item. + - `null` will focus the base composite element and users will be able to + navigate out of it using arrow keys. + - If `currentId` is initially set to `null`, the base composite element itself + will have focus and users will be able to navigate to it using arrow keys. +- **`loop`** boolean | "horizontal" | "vertical" On + one-dimensional composites: + + - `true` loops from the last item to the first item and vice-versa. + - `horizontal` loops only if `orientation` is `horizontal` or not set. + - `vertical` loops only if `orientation` is `vertical` or not set. + - If `currentId` is initially set to `null`, the composite element will be + focused in between the last and first items. + + On two-dimensional composites: + + - `true` loops from the last row/column item to the first item in the same + row/column and vice-versa. If it's the last item in the last row, it moves + to the first item in the first row and vice-versa. + - `horizontal` loops only from the last row item to the first item in the same + row. + - `vertical` loops only from the last column item to the first item in the + column row. + - If `currentId` is initially set to `null`, vertical loop will have no effect + as moving down from the last row or up from the first row will focus the + composite element. + - If `wrap` matches the value of `loop`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. + +- **`wrap`** boolean | "horizontal" | "vertical" + **Has effect only on two-dimensional composites**. If enabled, moving to the + next item from the last one in a row or column will focus the first item in + the next row or column and vice-versa. + - `true` wraps between rows and columns. + - `horizontal` wraps only between rows. + - `vertical` wraps only between columns. + - If `loop` matches the value of `wrap`, it'll wrap between the last item in + the last row or column and the first item in the first row or column and + vice-versa. +- **`shift`** boolean **Has effect only on two-dimensional + composites**. If enabled, moving up or down when there's no next item or the + next item is disabled will shift to the item right before it. +- **`unstable_moves`** โš ๏ธ number + Stores the number of moves that have been performed by calling `move`, `next`, + `previous`, `up`, `down`, `first` or `last`. +- **`registerItem`** (item: Item) => void Registers a composite + item. +- **`unregisterItem`** (id: string) => void Unregisters a + composite item. +- **`registerGroup`** (group: Group) => void Registers a + composite group. +- **`unregisterGroup`** (id: string) => void Unregisters a + composite group. +- **`move`** (id: string | null) => void Moves focus to a given + item ID. +- **`next`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the next item. +- **`previous`** (unstable_allTheWay?: boolean | undefined) => + void Moves focus to the previous item. +- **`up`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item above. +- **`down`** (unstable_allTheWay?: boolean | undefined) => void + Moves focus to the item below. +- **`first`** () => void Moves focus to the first item. +- **`last`** () => void Moves focus to the last item. +- **`sort`** () => void Sorts the `composite.items` based on + the items position in the DOM. This is especially useful after modifying the + composite items order in the DOM. Most of the time, though, you don't need to + manually call this function as the re-ordering happens automatically. +- **`unstable_setVirtual`** โš ๏ธ (value: + SetStateAction<boolean>) => void Sets `virtual`. +- **`setRTL`** (value: SetStateAction<boolean>) => void + Sets `rtl`. +- **`setOrientation`** + (value: + SetStateAction<"horizontal" | "vertical... Sets + `orientation`. +- **`setCurrentId`** + (value: + SetStateAction<string | null | undefine... Sets `currentId`. This + is different from `composite.move` as this only updates the `currentId` state + without moving focus. When the composite widget gets focused by the user, the + item referred by the `currentId` state will get focus. +- **`setLoop`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `loop`. +- **`setWrap`** + (value: + SetStateAction<boolean | "horizontal" |... Sets `wrap`. +- **`setShift`** (value: SetStateAction<boolean>) => + void Sets `shift`. +- **`reset`** () => void Resets to initial state. +- **`animated`** number | boolean If `true`, `animating` will be + set to `true` when `visible` is updated. It'll wait for `stopAnimation` to be + called or a CSS transition ends. If `animated` is set to a `number`, + `stopAnimation` will be called only after the same number of milliseconds have + passed. +- **`animating`** boolean Whether it's animating or not. +- **`hide`** () => void Changes the `visible` state to `false` +- **`toggle`** () => void Toggles the `visible` state +- **`setVisible`** (value: SetStateAction<boolean>) => + void Sets `visible`. +- **`setAnimated`** (value: SetStateAction<number | boolean>) + => void Sets `animated`. +- **`stopAnimation`** () => void Stops animation. It's called + automatically if there's a CSS transition. +- **`modal`** boolean Toggles Dialog's `modal` state. + - Non-modal: `preventBodyScroll` doesn't work and focus is free. + - Modal: `preventBodyScroll` is automatically enabled, focus is trapped within + the dialog and the dialog is rendered within a `Portal` by default. +- **`setModal`** (value: SetStateAction<boolean>) => + void Sets `modal`. +- **`unstable_referenceRef`** โš ๏ธ + RefObject<HTMLElement | null> The reference element. +- **`placement`** + "auto-start" + | "auto" | "auto-end" | "top-start... Actual + `placement`. +- **`place`** (value: SetStateAction<Placement>) => + void Change the `placement` state. +- **`time`** Date + +- **`hours`** number[] + +- **`minutes`** number[] + +- **`meridies`** string[] + +- **`hourState`** + { + baseId: string; unstable_idCountRef: MutableR... + +- **`minuteState`** + { + baseId: string; unstable_idCountRef: MutableR... + +- **`meridiesState`** + { + baseId: string; unstable_idCountRef: MutableR... + +
+ +## Composition + +- TimePicker uses [usePickerBase](undefined) +- TimePickerColumn uses [useComposite](https://reakit.io/docs/composite) +- TimePickerColumnValue uses [useButton](https://reakit.io/docs/button) and + [useCompositeItem](https://reakit.io/docs/composite) +- TimePickerContent uses [usePickerBaseContent](undefined) +- TimePickerSegment uses [useSegment](undefined) +- TimePickerSegmentField uses [useSegmentField](undefined) +- TimePickerTrigger uses [usePickerBaseTrigger](undefined) + +## Example + +```js +import React from "react"; +import { + TimePicker, + TimePickerColumn, + TimePickerSegment, + TimePickerTrigger, + TimePickerContent, + useTimePickerState, + TimePickerColumnValue, + TimePickerSegmentField, +} from "renderless-components"; + +const CalendarIcon = () => ( + +); + +export const App = props => { + const state = useTimePickerState(props); + + return ( + <> + +
+ + {state.segments.map((segment, i) => ( + + ))} + + + + +
+
+ + + {state.hours.map(n => { + return ( + + {n} + + ); + })} + + + {state.minutes.map((n, i) => { + return ( + + {n} + + ); + })} + + + {state.meridies.map((n, i) => { + return ( + + {n} + + ); + })} + + + + ); +}; + +export default App; +``` diff --git a/docs/toast.md b/docs/toast.md new file mode 100644 index 000000000..bd3ae6be5 --- /dev/null +++ b/docs/toast.md @@ -0,0 +1,54 @@ +## Toast + +Accessible `Toast` component. + +[Toast CSS Animated - Open On Sandbox](https://codesandbox.io/s/ze954) + +[Toast - Open On Sandbox](https://codesandbox.io/s/clz0m) + +## Example + +```js +import React from "react"; +import { ToastProvider } from "renderless-components"; + +import { Variants, Placements } from "./Utils.component"; + +export const App = () => { + return ( + { + return ( +
+ {content} +
+ ); + }, + success: ({ hideToast, content, id }) => { + return ( +
+ {content} +
+ ); + }, + warning: ({ hideToast, content, id }) => { + return ( +
+ {content} +
+ ); + }, + }} + > + +
+ +
+ ); +}; + +export default App; +``` diff --git a/package.json b/package.json index 434f66538..58e8269e7 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,10 @@ "commit": "gacp", "contributors:add": "all-contributors add", "contributors:generate": "all-contributors generate", + "docs": "node scripts/builds/docs.js", "format": "prettier --write \"./**/*.{js,ts,css,less,json,md,html,yml,yaml,pcss,jsx,tsx}\"", "generatejs": "node scripts/generate-js", - "keys": "node scripts/build/keys", + "keys": "node scripts/builds/keys", "lint": "eslint . --ext .tsx,.ts,.jsx,.js --fix", "lint:package": "sort-package-json", "prepublishOnly": "yarn test && yarn build", @@ -84,6 +85,7 @@ "@testing-library/react": "11.1.0", "@testing-library/react-hooks": "3.4.2", "@testing-library/user-event": "12.1.10", + "@textlint/markdown-to-ast": "^6.2.5", "@types/jest": "26.0.15", "@types/jest-axe": "3.5.1", "@types/jest-in-case": "1.0.3", @@ -95,12 +97,15 @@ "@typescript-eslint/eslint-plugin": "4.6.0", "@typescript-eslint/parser": "4.6.0", "all-contributors-cli": "^6.19.0", + "ast-to-markdown": "^1.0.0", + "axios": "^0.21.0", "babel-eslint": "10.1.0", "babel-jest": "^26.6.1", "babel-loader": "^8.1.0", "babel-plugin-chakra-ui": "1.0.0-rc.7", "babel-plugin-date-fns": "^2.0.0", "chalk": "4.1.0", + "codesandbox": "^2.2.1", "concurrently": "5.3.0", "conventional-github-releaser": "3.1.5", "cross-env": "7.0.2", @@ -124,6 +129,8 @@ "jest-matcher-utils": "26.6.1", "lint-staged": "10.5.1", "lodash": "4.17.20", + "markdown-to-ast": "^6.0.3", + "md-node-inject": "^1.0.1", "mockdate": "^3.0.2", "outdent": "^0.7.1", "postcss-import": "^12.0.1", @@ -144,11 +151,13 @@ "sort-package-json": "1.46.1", "standard-version": "9.0.0", "storybook-addon-preview": "^2.1.0", + "strip-comments": "^2.0.1", "ts-jest": "26.4.3", - "ts-morph": "8.1.2", + "ts-morph": "^8.2.0", "ts-node": "^9.0.0", "tsd": "^0.13.1", - "typescript": "4.0.5" + "typescript": "4.0.5", + "yaml": "^1.10.0" }, "peerDependencies": { "react": "^16.8.0", diff --git a/scripts/builds/docs.js b/scripts/builds/docs.js new file mode 100644 index 000000000..ff23af4fd --- /dev/null +++ b/scripts/builds/docs.js @@ -0,0 +1,49 @@ +const fs = require("fs"); +const path = require("path"); +const chalk = require("chalk"); + +const mdPrettify = require("../utils/md-prettify"); +const injectProps = require("../utils/inject-props"); +const { walkSync, createFile } = require("../utils/fs-utils"); +const injectExamples = require("../utils/inject-examples"); +const injectCsbLinks = require("../utils/inject-csb-links"); +const injectComposition = require("../utils/inject-composition"); + +const docsFolder = path.resolve(process.cwd(), "docs"); + +const injections = async templateFilePath => { + const fileName = path.basename(templateFilePath); + const template = fs.readFileSync(templateFilePath, "utf-8"); + const logProgress = (msg, fileName) => { + console.log(chalk.red.yellow(`${msg}:`, chalk.red.greenBright(fileName))); + }; + + const injectedExamplesTemplate = injectExamples(template); + logProgress(`Injected examples`, fileName); + + const injectedCompositionTemplate = injectComposition( + injectedExamplesTemplate, + ); + logProgress(`Injected composition`, fileName); + + const injectedPropsTemplate = injectProps(injectedCompositionTemplate); + logProgress(`Injected props`, fileName); + + const finalReadme = await injectCsbLinks(injectedPropsTemplate); + logProgress(`Injected sandbox`, fileName); + + createFile(path.join(docsFolder, fileName), mdPrettify(finalReadme)); + logProgress(`Docs generated`, fileName); +}; + +if (process.argv[2]) { + const templateFile = path.join("docs-templates", `${process.argv[2]}.md`); + const templateFilePath = path.resolve(process.cwd(), templateFile); + + injections(templateFilePath); +} else { + const docsTemplatesFolder = path.resolve(process.cwd(), "docs-templates"); + + const docsTemplateFiles = walkSync(docsTemplatesFolder); + docsTemplateFiles.forEach(injections); +} diff --git a/scripts/build/keys.js b/scripts/builds/keys.js similarity index 100% rename from scripts/build/keys.js rename to scripts/builds/keys.js diff --git a/scripts/generate-js.js b/scripts/generate-js.js index 050700431..8d6844c96 100644 --- a/scripts/generate-js.js +++ b/scripts/generate-js.js @@ -4,56 +4,20 @@ const chalk = require("chalk"); const globFs = require("glob-fs")(); const outdent = require("outdent"); const { camelCase, startCase } = require("lodash"); -const transpileTs = require("./transpile-ts"); - -// Create a new folder at the specified path -function createDirectory(path) { - try { - if (!fs.existsSync(path)) { - fs.mkdirSync(path, { recursive: true }); - } - } catch (err) { - console.error(`[createDirectory]: Failed to create director at ${path}`); - } -} - -function createFile(filePath, fileContent = "") { - fs.writeFile(filePath, fileContent, error => { - if (error) { - console.log(`Failed to create ${filePath}`, chalk.red.bold("ERROR")); - throw error; - } - }); -} -function walkSync(dir, filelist = []) { - const files = fs.readdirSync(dir); - - files.forEach(function (file) { - const fullPath = path.join(dir, file); - - if (isDirectory(fullPath)) { - filelist = walkSync(fullPath, filelist); - } else { - filelist.push(fullPath); - } - }); - - return filelist; -} +const { + walkSync, + createFile, + getDirectories, + createDirectory, +} = require("./fs-utils"); +const transpileTs = require("./transpile-ts"); // -> get all the component folders [accordion, breadcrumb...] // -> find all the .components inside the folders // -> create object with component pairs // { accordion: [Accordion.component.tsx, AccordionStyled.component.tsx] } // -> loop through them and create template.ts file -const isDirectory = source => fs.lstatSync(source).isDirectory(); -const getDirectories = source => - fs - .readdirSync(source) - .map(name => path.join(source, name)) - .filter(isDirectory); - function getComponentFolderPairs() { const componentFolders = getDirectories( path.resolve(__dirname, "../src"), diff --git a/scripts/utils/fs-utils.js b/scripts/utils/fs-utils.js new file mode 100644 index 000000000..ffabd0ff3 --- /dev/null +++ b/scripts/utils/fs-utils.js @@ -0,0 +1,54 @@ +const fs = require("fs"); +const path = require("path"); +const chalk = require("chalk"); + +// Create a new folder at the specified path +function createDirectory(path) { + try { + if (!fs.existsSync(path)) { + fs.mkdirSync(path, { recursive: true }); + } + } catch (err) { + console.error(`[createDirectory]: Failed to create director at ${path}`); + } +} + +function createFile(filePath, fileContent = "") { + fs.writeFile(filePath, fileContent, error => { + if (error) { + console.log(`Failed to create ${filePath}`, chalk.red.bold("ERROR")); + throw error; + } + }); +} + +const isDirectory = source => fs.lstatSync(source).isDirectory(); +const getDirectories = source => + fs + .readdirSync(source) + .map(name => path.join(source, name)) + .filter(isDirectory); + +function walkSync(dir, filelist = []) { + const files = fs.readdirSync(dir); + + files.forEach(function (file) { + const fullPath = path.join(dir, file); + + if (isDirectory(fullPath)) { + filelist = walkSync(fullPath, filelist); + } else { + filelist.push(fullPath); + } + }); + + return filelist; +} + +module.exports = { + walkSync, + isDirectory, + createFile, + createDirectory, + getDirectories, +}; diff --git a/scripts/utils.js b/scripts/utils/index.js similarity index 97% rename from scripts/utils.js rename to scripts/utils/index.js index 8def29b71..c8fa7f279 100644 --- a/scripts/utils.js +++ b/scripts/utils/index.js @@ -1,15 +1,15 @@ // Taken from: https://github.com/reakit/reakit/blob/6f6d1ad9177156cafa4adf9c987a43c79a1bbb90/scripts/build/utils.js -const { join, dirname, basename } = require("path"); -const { toUpper, snakeCase, isEqual } = require("lodash"); -const prettier = require("prettier"); const { - readdirSync, - writeFileSync, lstatSync, existsSync, + readdirSync, + writeFileSync, } = require("fs-extra"); -const { Project } = require("ts-morph"); const chalk = require("chalk"); +const prettier = require("prettier"); +const { join, dirname, basename } = require("path"); +const { toUpper, snakeCase, isEqual } = require("lodash"); +const { Project } = require("ts-morph"); function log(...args) { console.log(...args); @@ -164,6 +164,7 @@ function getDeclaration(symbol) { * @param {import("ts-morph").Symbol} symbol */ function getJsDocs(symbol) { + if (!getDeclaration(symbol).getJsDocs) return; const jsDocs = getDeclaration(symbol).getJsDocs(); return jsDocs[jsDocs.length - 1]; } @@ -367,6 +368,16 @@ function makeKeys(rootPath) { } module.exports = { + getPackage, hasTSConfig, makeKeys, + getProps, + getEscapedName, + getModuleName, + getDeclaration, + isOptionsDeclaration, + isStateReturnDeclaration, + sortSourceFiles, + getPublicFiles, + getJsDocs, }; diff --git a/scripts/utils/inject-composition.js b/scripts/utils/inject-composition.js new file mode 100644 index 000000000..8ff4a0d47 --- /dev/null +++ b/scripts/utils/inject-composition.js @@ -0,0 +1,95 @@ +const fs = require("fs"); +const path = require("path"); +const outdent = require("outdent"); +const { Project, ts } = require("ts-morph"); + +const injectMdContent = require("./inject-md-content"); +const { getEscapedName, getPublicFiles, sortSourceFiles } = require("./index"); + +const COMPOSE_INJECT_FLAG = /\<\!\-\- INJECT_COMPOSITION (.*) \-\-\>/m; + +const injectComposition = docsTemplate => { + return injectMdContent( + docsTemplate, + COMPOSE_INJECT_FLAG, + (line, regexMatched) => { + const composites = getComposition( + path.join(process.cwd(), regexMatched[1]), + ); + return getMarkdown(composites); + }, + ); +}; + +module.exports = injectComposition; + +function getComposition(rootPath) { + const project = new Project({ + tsConfigFilePath: path.join(process.cwd(), "tsconfig.json"), + addFilesFromTsConfig: false, + }); + + const publicPaths = Object.values(getPublicFiles(rootPath)); + const sourceFiles = project.addSourceFilesAtPaths(publicPaths); + project.resolveSourceFileDependencies(); + + let compose = {}; + sortSourceFiles(sourceFiles).forEach(sourceFile => { + sourceFile.forEachDescendant(node => { + const moduleName = sourceFile.getBaseNameWithoutExtension(); + if ( + ts.SyntaxKind.PropertyAssignment && + getEscapedName(node) === "compose" + ) { + const ValueDeclaration = node.getSymbol().getValueDeclaration(); + const initializer = ValueDeclaration.compilerNode.initializer; + + if (initializer.kind === ts.SyntaxKind.ArrayLiteralExpression) { + compose[moduleName] = initializer.elements.map(v => v.escapedText); + } + + if (initializer.kind === ts.SyntaxKind.Identifier) { + compose[moduleName] = initializer.escapedText; + } + } + }); + }); + + return compose; +} + +function getMarkdown(compose) { + const hookLinks = { + useComposite: "https://reakit.io/docs/composite", + useCompositeItem: "https://reakit.io/docs/composite", + unstable_useId: "https://reakit.io/docs/id", + useDisclosureContent: "https://reakit.io/docs/disclosure", + useButton: "https://reakit.io/docs/button", + useBox: "https://reakit.io/docs/box", + useClickable: "https://reakit.io/docs/clickable", + useLink: "./link.md", + }; + + const formatter = new Intl.ListFormat("en", { + style: "long", + type: "conjunction", + }); + const content = Object.keys(compose).map(moduleName => { + const module = compose[moduleName]; + + const composition = + typeof module === "string" + ? `[${module}](${hookLinks[module]})` + : formatter.format( + module.map(item => { + return `[${item}](${hookLinks[item]})`; + }), + ); + + return outdent` + - ${moduleName} uses ${composition} + `; + }); + + return content.join("\n"); +} diff --git a/scripts/utils/inject-csb-links.js b/scripts/utils/inject-csb-links.js new file mode 100644 index 000000000..6bb8bb1cf --- /dev/null +++ b/scripts/utils/inject-csb-links.js @@ -0,0 +1,116 @@ +const fs = require("fs"); +const path = require("path"); +const yaml = require("yaml"); +const axios = require("axios"); +const { outdent } = require("outdent"); +const { getParameters } = require("codesandbox/lib/api/define"); + +const CODESANDBOX_REGEX = /\<\!\-\- CODESANDBOX[\s\S]*?.*\-\-\>/gm; +const CODESANDBOX_GLOBAL_FLAG = new RegExp(CODESANDBOX_REGEX.source, "gm"); +const CODESANDBOX_REPLACE_FLAG = new RegExp(CODESANDBOX_REGEX.source, "m"); + +const injectCsbLinks = async docsTemplate => { + const regexMatched = docsTemplate.match(CODESANDBOX_GLOBAL_FLAG); + if (!regexMatched) return docsTemplate; + + const promises = regexMatched.map(async match => { + try { + const ymlString = match + .replace("", ""); + const parsed = yaml.parse(ymlString); + const linkTitle = parsed.link_title || "Open On CodeSandbox"; + + const sandboxLink = await getSandboxShortURL(parsed); + + docsTemplate = docsTemplate.replace( + CODESANDBOX_REPLACE_FLAG, + `[${linkTitle}](${sandboxLink})`, + ); + } catch (e) { + console.log(e); + } + }); + + await Promise.all(promises); + + return docsTemplate; +}; + +module.exports = injectCsbLinks; + +const getSandboxShortURL = async parsed => { + const defineLink = getSandboxDefineLink( + { + js: readFile(parsed.js), + css: readFile(parsed.css), + utils: readFile(parsed.utils), + }, + parsed.deps && parsed.deps, + ); + + // fetching the sandbox_id, otherwise the URL would be longer + const response = await axios.get(`${defineLink}&json=1`); + const sandboxLink = `https://codesandbox.io/s/${response.data.sandbox_id}`; + + return sandboxLink; +}; + +const getSandboxDefineLink = (files, extraDeps) => { + const deps = { + reakit: "latest", + "renderless-components": "0.1.1-beta.3", + react: "^16.8.0", + "react-dom": "^16.8.0", + "react-scripts": "^3.4.3", + ...(extraDeps && + extraDeps.reduce((curr, next) => { + return { ...curr, ...resolveVersion(next) }; + }, {})), + }; + + const parameters = getParameters({ + files: { + "src/index.js": { + content: outdent` + import * as ReactDOM from "react-dom"; + import * as React from "react"; + import App from "./App"; + import "./styles.css"; + + const rootElement = document.getElementById("root"); + ReactDOM.render(, rootElement); + `, + }, + "src/App.js": files.js && { content: files.js }, + "src/styles.css": files.css && { content: files.css }, + "src/Utils.component.js": files.utils && { + content: files.utils, + }, + "package.json": { + content: { dependencies: { ...deps } }, + }, + }, + }); + + return `https://codesandbox.io/api/v1/sandboxes/define?parameters=${parameters}`; +}; + +const readFile = url => { + try { + return fs.readFileSync(path.join(process.cwd(), url), { + encoding: "utf-8", + }); + } catch (er) { + return; + } +}; + +const resolveVersion = userModule => { + const packageDendencies = {}; + const result = /^(@*[^@]+)@*([^@/]+)*$/g.exec(userModule); + const name = result ? result[1] : userModule; + const version = result && result[2] ? result[2] : "latest"; + packageDendencies[name] = version; + return packageDendencies; +}; diff --git a/scripts/utils/inject-examples.js b/scripts/utils/inject-examples.js new file mode 100644 index 000000000..0ca7c0f65 --- /dev/null +++ b/scripts/utils/inject-examples.js @@ -0,0 +1,31 @@ +const fs = require("fs"); +const path = require("path"); +const strip = require("strip-comments"); +const prettier = require("prettier/standalone"); +const parserBabel = require("prettier/parser-babel"); + +const injectMdContent = require("./inject-md-content"); +const prettierConfig = require("../../.prettierrc.json"); + +const CODE_EXAMPLE_FLAG = /\<\!\-\- IMPORT_EXAMPLE (.*) \-\-\>/m; + +const injectExamples = docsTemplate => { + return injectMdContent( + docsTemplate, + CODE_EXAMPLE_FLAG, + (line, regexMatched) => { + const importString = regexMatched[1]; + const importPath = path.resolve(process.cwd(), importString); + + const code = fs.readFileSync(importPath, { encoding: "utf-8" }); + const prettifiedCode = prettier.format(strip(code), { + parser: "babel", + plugins: [parserBabel], + ...prettierConfig, + }); + return prettifiedCode.replace(/\n.*$/, ""); + }, + ); +}; + +module.exports = injectExamples; diff --git a/scripts/utils/inject-md-content.js b/scripts/utils/inject-md-content.js new file mode 100644 index 000000000..42b3bc5bb --- /dev/null +++ b/scripts/utils/inject-md-content.js @@ -0,0 +1,14 @@ +const injectMdContent = (md, regex, callback) => { + return md + .split("\n") + .map(line => { + const flagMatch = line.match(regex); + if (flagMatch) { + return callback(line, flagMatch); + } + return line; + }) + .join("\n"); +}; + +module.exports = injectMdContent; diff --git a/scripts/utils/inject-props.js b/scripts/utils/inject-props.js new file mode 100644 index 000000000..c2f0f77bb --- /dev/null +++ b/scripts/utils/inject-props.js @@ -0,0 +1,199 @@ +const path = require("path"); +const outdent = require("outdent"); +const { Project, ts } = require("ts-morph"); + +const { + getProps, + getJsDocs, + getPublicFiles, + getModuleName, + getEscapedName, + getDeclaration, + sortSourceFiles, + isOptionsDeclaration, + isStateReturnDeclaration, +} = require("./index"); +const injectMdContent = require("./inject-md-content"); + +const PROPS_INJECT_FLAG = /\<\!\-\- INJECT_PROPS (.*) \-\-\>/m; + +const injectProps = docsTemplate => { + return injectMdContent( + docsTemplate, + PROPS_INJECT_FLAG, + (line, regexMatched) => { + const types = getPropTypes(path.join(process.cwd(), regexMatched[1])); + + return getPropTypesMarkdown(types); + }, + ); +}; + +module.exports = injectProps; + +/** + * Inject prop types tables into README.md files + * @param {string} rootPath + */ +function getPropTypes(rootPath) { + const stateTypes = []; + + const project = new Project({ + tsConfigFilePath: path.join(process.cwd(), "tsconfig.json"), + addFilesFromTsConfig: false, + }); + + const publicPaths = Object.values(getPublicFiles(rootPath)); + const sourceFiles = project.addSourceFilesAtPaths(publicPaths); + project.resolveSourceFileDependencies(); + const types = {}; + + sortSourceFiles(sourceFiles).forEach(sourceFile => { + sourceFile.forEachChild(node => { + if (isStateReturnDeclaration(node)) { + const propTypes = createPropTypeObjects(rootPath, node); + stateTypes.push(...propTypes.map(prop => prop.name)); + } + if (isPropsDeclaration(node)) { + const moduleName = getModuleName(node); + const propTypes = createPropTypeObjects(rootPath, node); + + if (isInitialStateDeclaration(node)) { + types[moduleName] = propTypes; + } else { + const propTypesWithoutState = propTypes.filter( + prop => !stateTypes.includes(prop.name), + ); + const propTypesReturnedByState = propTypes.filter(prop => + stateTypes.includes(prop.name), + ); + types[moduleName] = propTypesWithoutState; + types[moduleName].stateProps = propTypesReturnedByState; + } + } + }); + }); + + return types; +} + +/** + * @param {string} rootPath + * @param {import("ts-morph").Node} node + */ +function createPropTypeObjects(rootPath, node) { + return getProps(node).map(prop => createPropTypeObject(rootPath, prop)); +} + +/** + * @param {string} rootPath + * @param {import("ts-morph").Symbol} prop + */ +function getPropType(rootPath, prop) { + const declaration = getDeclaration(prop); + const type = declaration + .getType() + .getText(undefined, ts.TypeFormatFlags.InTypeAlias); + + const encode = text => + text.replace(/[\u00A0-\u9999<>&"]/gim, i => `&#${i.charCodeAt(0)};`); + + if (type.length > 50) { + return outdent`${encode( + type.substring(0, 47), + )}...`; + } + return `${encode(type)}`; +} + +/** + * @param {string} rootPath + * @param {import("ts-morph").Symbol} prop + */ +function createPropTypeObject(rootPath, prop) { + return { + name: prop.getEscapedName(), + description: getComment(prop), + type: getPropType(rootPath, prop), + }; +} + +/** + * @param {import("ts-morph").Node} node + */ +function isInitialStateDeclaration(node) { + const kindName = node.getKindName(); + const escapedName = getEscapedName(node); + return ( + kindName === "TypeAliasDeclaration" && /.+InitialState$/.test(escapedName) + ); +} + +/** + * @param {import("ts-morph").Symbol} symbol + * @returns {string} + */ +function getComment(symbol) { + const jsDocs = getJsDocs(symbol); + if (!jsDocs) return ""; + return jsDocs.getDescription().trim(); +} + +/** + * @param {import("ts-morph").Node} node + */ +function isPropsDeclaration(node) { + return isOptionsDeclaration(node) || isInitialStateDeclaration(node); +} + +/** + * @param {ReturnType} prop + */ +function getPropTypesRow(prop) { + const symbol = /unstable_/.test(prop.name) + ? ' โš ๏ธ' + : ""; + const name = `**\`${prop.name}\`**${symbol} `; + + return outdent` + - ${name} + ${prop.type} + ${prop.description.split("\n\n").join("\n\n ")} + `; +} + +function getSummaryDetails(stateProps) { + return outdent` +
${stateProps.length} state props + > These props are returned by the state hook. You can spread them into this component (\`{...state}\`) or pass them separately. You can also provide these props from your own state logic. + + ${stateProps.map(getPropTypesRow).join("\n")} + +
+ `; +} + +/** + * @param {Record>} types + */ +function getPropTypesMarkdown(types) { + const content = Object.keys(types) + .map(title => { + const props = types[title]; + const rows = props.map(getPropTypesRow).join("\n"); + const stateProps = props.stateProps || []; + const hiddenRows = stateProps.length ? getSummaryDetails(stateProps) : ""; + + return outdent` + ### \`${title}\` + ${rows || (hiddenRows ? "" : "No props to show")} + ${hiddenRows} + `; + }) + .join("\n\n"); + + return outdent` + + ${content} + `; +} diff --git a/scripts/utils/md-prettify.js b/scripts/utils/md-prettify.js new file mode 100644 index 000000000..d9e148e61 --- /dev/null +++ b/scripts/utils/md-prettify.js @@ -0,0 +1,14 @@ +const prettier = require("prettier/standalone"); +const markdownParser = require("prettier/parser-markdown"); + +const prettierConfig = require("../../.prettierrc.json"); + +const mdPrettify = docsTemplate => { + return prettier.format(docsTemplate, { + parser: "markdown", + plugins: [markdownParser], + ...prettierConfig, + }); +}; + +module.exports = mdPrettify; diff --git a/src/accordion/Accordion.ts b/src/accordion/Accordion.ts index f32610b10..6a64ea106 100644 --- a/src/accordion/Accordion.ts +++ b/src/accordion/Accordion.ts @@ -3,12 +3,6 @@ import { CompositeOptions, CompositeHTMLProps, useComposite } from "reakit"; import { ACCORDION_KEYS } from "./__keys"; -export type AccordionOptions = CompositeOptions; - -export type AccordionHTMLProps = CompositeHTMLProps; - -export type AccordionProps = AccordionOptions & AccordionHTMLProps; - export const useAccordion = createHook({ name: "Accordion", compose: useComposite, @@ -33,3 +27,9 @@ export const Accordion = createComponent({ memo: true, useHook: useAccordion, }); + +export type AccordionOptions = CompositeOptions; + +export type AccordionHTMLProps = CompositeHTMLProps; + +export type AccordionProps = AccordionOptions & AccordionHTMLProps; diff --git a/src/accordion/AccordionPanel.ts b/src/accordion/AccordionPanel.ts index e53f01b7c..e553b5cf6 100644 --- a/src/accordion/AccordionPanel.ts +++ b/src/accordion/AccordionPanel.ts @@ -1,10 +1,10 @@ import { - DisclosureContentOptions, - DisclosureContentHTMLProps, - useDisclosureContent, unstable_useId, unstable_IdOptions, unstable_IdHTMLProps, + useDisclosureContent, + DisclosureContentOptions, + DisclosureContentHTMLProps, } from "reakit"; import * as React from "react"; import { useForkRef } from "reakit-utils"; @@ -12,30 +12,7 @@ import { createHook, createComponent } from "reakit-system"; import { ACCORDION_PANEL_KEYS } from "./__keys"; import { AccordionStateReturn } from "./AccordionState"; - -export type AccordionPanelOptions = DisclosureContentOptions & - unstable_IdOptions & - Pick< - AccordionStateReturn, - | "registerPanel" - | "unregisterPanel" - | "panels" - | "items" - | "allowMultiple" - | "selectedId" - | "selectedIds" - > & { - /** - * Accordion's id - */ - accordionId?: string; - }; - -export type AccordionPanelHTMLProps = DisclosureContentHTMLProps & - unstable_IdHTMLProps; - -export type AccordionPanelProps = AccordionPanelOptions & - AccordionPanelHTMLProps; +import { getAccordionId, isPanelVisible } from "./helpers"; export const useAccordionPanel = createHook< AccordionPanelOptions, @@ -80,58 +57,26 @@ export const AccordionPanel = createComponent({ useHook: useAccordionPanel, }); -/** - * When is used without accordionId: - * - * - First render: getAccordionId will return undefined because options.panels - * doesn't contain the current panel yet (registerPanel wasn't called yet). - * Thus registerPanel will be called without groupId (accordionId). - * - * - Second render: options.panels already contains the current panel (because - * registerPanel was called in the previous render). This means that we'll be - * able to get the related accordionId with the accordion panel index. Basically, - * we filter out all the accordions and panels that have already matched. In this - * phase, registerPanel will be called again with the proper groupId (accordionId). - * - * - In the third render, panel.groupId will be already defined, so we just - * return it. registerPanel is not called. - */ -function getAccordionId(options: AccordionPanelOptions) { - const { panels, id, items } = options; - const panel = panels?.find(p => p.id === id); - const accordionId = options.accordionId || panel?.groupId; - if (accordionId || !panel || !panels || !items) { - return accordionId; - } - - const panelIndex = getPanelIndex(panels, panel); - const accordionsWithoutPanel = getAccordionsWithoutPanel(items, panels); - return accordionsWithoutPanel[panelIndex]?.id || undefined; -} - -function getPanelIndex( - panels: AccordionPanelOptions["panels"], - panel: typeof panels[number], -) { - const panelsWithoutAccordionId = panels.filter(p => !p.groupId); - return panelsWithoutAccordionId.indexOf(panel); -} - -function getAccordionsWithoutPanel( - accordions: AccordionPanelOptions["items"], - panels: AccordionPanelOptions["panels"], -) { - const panelsAccordionIds = panels.map(panel => panel.groupId).filter(Boolean); - - return accordions.filter( - item => panelsAccordionIds.indexOf(item.id || undefined) === -1, - ); -} +export type AccordionPanelOptions = { + /** + * Accordion's id + */ + accordionId?: string; +} & DisclosureContentOptions & + unstable_IdOptions & + Pick< + AccordionStateReturn, + | "registerPanel" + | "unregisterPanel" + | "panels" + | "items" + | "allowMultiple" + | "selectedId" + | "selectedIds" + >; -function isPanelVisible(options: AccordionPanelOptions) { - const { allowMultiple, selectedId, selectedIds } = options; - const accordionId = getAccordionId(options); +export type AccordionPanelHTMLProps = DisclosureContentHTMLProps & + unstable_IdHTMLProps; - if (!allowMultiple) return accordionId ? selectedId === accordionId : false; - return accordionId ? selectedIds?.includes(accordionId) : false; -} +export type AccordionPanelProps = AccordionPanelOptions & + AccordionPanelHTMLProps; diff --git a/src/accordion/AccordionState.ts b/src/accordion/AccordionState.ts index 18add4657..433242314 100644 --- a/src/accordion/AccordionState.ts +++ b/src/accordion/AccordionState.ts @@ -1,23 +1,19 @@ import * as React from "react"; -import { useCompositeState } from "reakit"; import { useControllableState } from "@chakra-ui/hooks"; +import { CompositeInitialState, useCompositeState } from "reakit"; + import { + SelectedIdPair, AccordionState, AccordionActions, AccordionReturns, + AccordionPropsUnion, MultiOverloadReturn, + MultiAccordionProps, SingleOverloadReturn, - AccordionInitialState, - AccordionInitialStateMulti, - AccordionInitialStateSingle, - SelectedIdPair, + SingleAccordionProps, } from "./types"; -export type AccordionStateReturn = AccordionActions & - AccordionState & - AccordionReturns & - SelectedIdPair; - export function useAccordionState( props: AccordionInitialStateSingle, ): SingleOverloadReturn; @@ -146,3 +142,18 @@ export function useAccordionState( ...common, }; } + +export type AccordionInitialState = Partial< + AccordionPropsUnion & CompositeInitialState +>; +export type AccordionInitialStateSingle = Partial< + SingleAccordionProps & CompositeInitialState +>; +export type AccordionInitialStateMulti = Partial< + MultiAccordionProps & CompositeInitialState +>; + +export type AccordionStateReturn = AccordionState & + AccordionActions & + AccordionReturns & + SelectedIdPair; diff --git a/src/accordion/AccordionTrigger.ts b/src/accordion/AccordionTrigger.ts index d22fa2af4..5627c5fed 100644 --- a/src/accordion/AccordionTrigger.ts +++ b/src/accordion/AccordionTrigger.ts @@ -1,10 +1,10 @@ import { - useCompositeItem, - CompositeItemOptions, - CompositeItemHTMLProps, useButton, ButtonOptions, ButtonHTMLProps, + useCompositeItem, + CompositeItemOptions, + CompositeItemHTMLProps, } from "reakit"; import * as React from "react"; import { useLiveRef } from "reakit-utils"; @@ -13,26 +13,7 @@ import { createHook, createComponent } from "reakit-system"; import { ariaAttr } from "../utils"; import { ACCORDION_TRIGGER_KEYS } from "./__keys"; import { AccordionStateReturn } from "./AccordionState"; - -export type AccordionTriggerOptions = ButtonOptions & - CompositeItemOptions & - Pick, "manual"> & - Pick< - AccordionStateReturn, - | "panels" - | "select" - | "unSelect" - | "allowMultiple" - | "allowToggle" - | "selectedId" - | "selectedIds" - >; - -export type AccordionTriggerHTMLProps = ButtonHTMLProps & - CompositeItemHTMLProps; - -export type AccordionTriggerProps = AccordionTriggerOptions & - AccordionTriggerHTMLProps; +import { isAccordionSelected, useAccordionPanelId } from "./helpers"; export const useAccordionTrigger = createHook< AccordionTriggerOptions, @@ -162,19 +143,22 @@ export const AccordionTrigger = createComponent({ useHook: useAccordionTrigger, }); -function isAccordionSelected(options: AccordionTriggerOptions) { - const { id, allowMultiple, selectedId, selectedIds } = options; - if (!id) return; - - if (!allowMultiple) return selectedId === id; - return selectedIds?.includes(id); -} +export type AccordionTriggerOptions = ButtonOptions & + CompositeItemOptions & + Pick, "manual"> & + Pick< + AccordionStateReturn, + | "panels" + | "select" + | "unSelect" + | "allowMultiple" + | "allowToggle" + | "selectedId" + | "selectedIds" + >; -function useAccordionPanelId(options: AccordionTriggerOptions) { - const { panels, id } = options; +export type AccordionTriggerHTMLProps = ButtonHTMLProps & + CompositeItemHTMLProps; - return React.useMemo( - () => panels?.find(panel => panel.groupId === id)?.id || undefined, - [panels, id], - ); -} +export type AccordionTriggerProps = AccordionTriggerOptions & + AccordionTriggerHTMLProps; diff --git a/src/accordion/helpers.ts b/src/accordion/helpers.ts new file mode 100644 index 000000000..7e98b73ce --- /dev/null +++ b/src/accordion/helpers.ts @@ -0,0 +1,77 @@ +import * as React from "react"; + +import { AccordionPanelOptions } from "./AccordionPanel"; +import { AccordionTriggerOptions } from "./AccordionTrigger"; + +/** + * When is used without accordionId: + * + * - First render: getAccordionId will return undefined because options.panels + * doesn't contain the current panel yet (registerPanel wasn't called yet). + * Thus registerPanel will be called without groupId (accordionId). + * + * - Second render: options.panels already contains the current panel (because + * registerPanel was called in the previous render). This means that we'll be + * able to get the related accordionId with the accordion panel index. Basically, + * we filter out all the accordions and panels that have already matched. In this + * phase, registerPanel will be called again with the proper groupId (accordionId). + * + * - In the third render, panel.groupId will be already defined, so we just + * return it. registerPanel is not called. + */ +export function getAccordionId(options: AccordionPanelOptions) { + const { panels, id, items } = options; + const panel = panels?.find(p => p.id === id); + const accordionId = options.accordionId || panel?.groupId; + if (accordionId || !panel || !panels || !items) { + return accordionId; + } + + const panelIndex = getPanelIndex(panels, panel); + const accordionsWithoutPanel = getAccordionsWithoutPanel(items, panels); + return accordionsWithoutPanel[panelIndex]?.id || undefined; +} + +function getPanelIndex( + panels: AccordionPanelOptions["panels"], + panel: typeof panels[number], +) { + const panelsWithoutAccordionId = panels.filter(p => !p.groupId); + return panelsWithoutAccordionId.indexOf(panel); +} + +function getAccordionsWithoutPanel( + accordions: AccordionPanelOptions["items"], + panels: AccordionPanelOptions["panels"], +) { + const panelsAccordionIds = panels.map(panel => panel.groupId).filter(Boolean); + + return accordions.filter( + item => panelsAccordionIds.indexOf(item.id || undefined) === -1, + ); +} + +export function isPanelVisible(options: AccordionPanelOptions) { + const { allowMultiple, selectedId, selectedIds } = options; + const accordionId = getAccordionId(options); + + if (!allowMultiple) return accordionId ? selectedId === accordionId : false; + return accordionId ? selectedIds?.includes(accordionId) : false; +} + +export function isAccordionSelected(options: AccordionTriggerOptions) { + const { id, allowMultiple, selectedId, selectedIds } = options; + if (!id) return; + + if (!allowMultiple) return selectedId === id; + return selectedIds?.includes(id); +} + +export function useAccordionPanelId(options: AccordionTriggerOptions) { + const { panels, id } = options; + + return React.useMemo( + () => panels?.find(panel => panel.groupId === id)?.id || undefined, + [panels, id], + ); +} diff --git a/src/accordion/stories/AccordionBasic.stories.tsx b/src/accordion/stories/AccordionBasic.stories.tsx index a1d2d5f78..e6d7c3788 100644 --- a/src/accordion/stories/AccordionBasic.stories.tsx +++ b/src/accordion/stories/AccordionBasic.stories.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import { Meta } from "@storybook/react"; - import { CompositeState } from "reakit/ts"; -import { AccordionInitialState } from "../types"; + +import { AccordionInitialState } from "../AccordionState"; import { App as Accordion } from "./AccordionBasic.component"; import { createPreviewTabs } from "../../../scripts/create-preview-tabs"; import { accordionBasicTemplate, accordionBasicTemplateJs } from "./templates"; diff --git a/src/accordion/stories/AccordionStyled.stories.tsx b/src/accordion/stories/AccordionStyled.stories.tsx index 7e2f79818..6998bd128 100644 --- a/src/accordion/stories/AccordionStyled.stories.tsx +++ b/src/accordion/stories/AccordionStyled.stories.tsx @@ -1,3 +1,4 @@ +import "./AccordionStyled.css"; import * as React from "react"; import { Meta } from "@storybook/react"; import { CompositeState } from "reakit"; @@ -7,8 +8,8 @@ import { accordionStyledTemplateJs, accordionStyledCssTemplate, } from "./templates"; -import "./AccordionStyled.css"; -import { AccordionInitialState } from "../types"; + +import { AccordionInitialState } from "../AccordionState"; import { App as Accordion } from "./AccordionStyled.component"; import { createPreviewTabs } from "../../../scripts/create-preview-tabs"; diff --git a/src/accordion/types.ts b/src/accordion/types.ts index 25e692f9d..c35ffd3a1 100644 --- a/src/accordion/types.ts +++ b/src/accordion/types.ts @@ -1,10 +1,11 @@ -import { - CompositeState, - CompositeActions, - CompositeInitialState, -} from "reakit"; +import { CompositeState, CompositeActions } from "reakit"; export type AccordionState = CompositeState & { + /** + * Allow to toggle accordion items + * @default false + */ + allowToggle: boolean; /** * Allow to open multiple accordion items */ @@ -14,11 +15,6 @@ export type AccordionState = CompositeState & { * @default true */ manual: boolean; - /** - * Allow to toggle accordion items - * @default false - */ - allowToggle: boolean; /** * Lists all the panels. */ @@ -67,7 +63,13 @@ export type SelectedIdPair = { * @default [] */ selectedIds?: (string | null)[]; + /** + * Sets `selectedId`. + */ setSelectedId?: React.Dispatch>; + /** + * Sets `selectedIds`. + */ setSelectedIds?: React.Dispatch>; }; @@ -158,15 +160,5 @@ export type MultiOverloadReturn = AccordionActions & AccordionState & MultiReturn; -type AccordionProps = SingleAccordionProps | MultiAccordionProps; +export type AccordionPropsUnion = SingleAccordionProps | MultiAccordionProps; export type AccordionReturns = MultiReturn | SingleReturn; - -export type AccordionInitialState = Partial< - CompositeInitialState & AccordionProps ->; -export type AccordionInitialStateSingle = Partial< - CompositeInitialState & SingleAccordionProps ->; -export type AccordionInitialStateMulti = Partial< - CompositeInitialState & MultiAccordionProps ->; diff --git a/src/breadcrumbs/BreadcrumbLink.ts b/src/breadcrumbs/BreadcrumbLink.ts index 47ddb284c..2d4dc51e6 100644 --- a/src/breadcrumbs/BreadcrumbLink.ts +++ b/src/breadcrumbs/BreadcrumbLink.ts @@ -3,18 +3,6 @@ import { createComponent, createHook } from "reakit-system"; import { BREADCRUMB_LINK_KEYS } from "./__keys"; import { LinkHTMLProps, LinkOptions, useLink } from "../link"; -export type BreadcrumbLinkOptions = LinkOptions & { - /** - * If true, sets `aria-current: "page"` - */ - isCurrent?: boolean; -}; - -export type BreadcrumbLinkHTMLProps = LinkHTMLProps; - -export type BreadcrumbLinkProps = BreadcrumbLinkOptions & - BreadcrumbLinkHTMLProps; - export const useBreadcrumbLink = createHook< BreadcrumbLinkOptions, BreadcrumbLinkHTMLProps @@ -33,3 +21,15 @@ export const BreadcrumbLink = createComponent({ memo: true, useHook: useBreadcrumbLink, }); + +export type BreadcrumbLinkOptions = { + /** + * If true, sets `aria-current: "page"` + */ + isCurrent?: boolean; +} & LinkOptions; + +export type BreadcrumbLinkHTMLProps = LinkHTMLProps; + +export type BreadcrumbLinkProps = BreadcrumbLinkOptions & + BreadcrumbLinkHTMLProps; diff --git a/src/breadcrumbs/Breadcrumbs.ts b/src/breadcrumbs/Breadcrumbs.ts index 1c6e94cea..ad4e00d83 100644 --- a/src/breadcrumbs/Breadcrumbs.ts +++ b/src/breadcrumbs/Breadcrumbs.ts @@ -1,12 +1,6 @@ import { BoxHTMLProps, BoxOptions, useBox } from "reakit"; import { createComponent, createHook } from "reakit-system"; -export type BreadcrumbsOptions = BoxOptions; - -export type BreadcrumbsHTMLProps = BoxHTMLProps; - -export type BreadcrumbProps = BreadcrumbsOptions & BreadcrumbsHTMLProps; - export const useBreadcrumbs = createHook< BreadcrumbsOptions, BreadcrumbsHTMLProps @@ -24,3 +18,9 @@ export const Breadcrumbs = createComponent({ memo: true, useHook: useBreadcrumbs, }); + +export type BreadcrumbsOptions = BoxOptions; + +export type BreadcrumbsHTMLProps = BoxHTMLProps; + +export type BreadcrumbProps = BreadcrumbsOptions & BreadcrumbsHTMLProps; diff --git a/src/calendar/Calendar.ts b/src/calendar/Calendar.ts index 5cc3adfdd..b0dff922b 100644 --- a/src/calendar/Calendar.ts +++ b/src/calendar/Calendar.ts @@ -9,13 +9,6 @@ import { createComponent, createHook } from "reakit-system"; import { CALENDAR_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; -export type CalendarOptions = BoxOptions & - Pick; - -export type CalendarHTMLProps = BoxHTMLProps; - -export type CalendarProps = CalendarOptions & CalendarHTMLProps; - export const useCalendar = createHook({ name: "Calendar", compose: useBox, @@ -35,3 +28,10 @@ export const Calendar = createComponent({ memo: true, useHook: useCalendar, }); + +export type CalendarOptions = Pick & + BoxOptions; + +export type CalendarHTMLProps = BoxHTMLProps; + +export type CalendarProps = CalendarOptions & CalendarHTMLProps; diff --git a/src/calendar/CalendarButton.ts b/src/calendar/CalendarButton.ts index 0c2e3bb52..c28481a9e 100644 --- a/src/calendar/CalendarButton.ts +++ b/src/calendar/CalendarButton.ts @@ -10,28 +10,6 @@ import { ButtonHTMLProps, ButtonOptions, useButton } from "reakit"; import { CALENDAR_BUTTON_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; -export type CalendarGoto = - | "nextMonth" - | "previousMonth" - | "nextYear" - | "previousYear"; - -export type CalendarButtonOptions = ButtonOptions & - Pick< - CalendarStateReturn, - | "focusNextMonth" - | "focusPreviousMonth" - | "focusPreviousYear" - | "focusNextYear" - > & { - goto: CalendarGoto; - }; - -export type CalendarButtonHTMLProps = ButtonHTMLProps; - -export type CalendarButtonProps = CalendarButtonOptions & - CalendarButtonHTMLProps; - export const useCalendarButton = createHook< CalendarButtonOptions, CalendarButtonHTMLProps @@ -81,3 +59,25 @@ export const CalendarButton = createComponent({ memo: true, useHook: useCalendarButton, }); + +export type CalendarButtonOptions = { + goto: CalendarGoto; +} & Pick< + CalendarStateReturn, + | "focusNextMonth" + | "focusPreviousMonth" + | "focusPreviousYear" + | "focusNextYear" +> & + ButtonOptions; + +export type CalendarButtonHTMLProps = ButtonHTMLProps; + +export type CalendarButtonProps = CalendarButtonOptions & + CalendarButtonHTMLProps; + +export type CalendarGoto = + | "nextMonth" + | "previousMonth" + | "nextYear" + | "previousYear"; diff --git a/src/calendar/CalendarCell.ts b/src/calendar/CalendarCell.ts index a5abe0fb9..18a6c2cae 100644 --- a/src/calendar/CalendarCell.ts +++ b/src/calendar/CalendarCell.ts @@ -14,21 +14,6 @@ import { CALENDAR_CELL_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; import { RangeCalendarStateReturn } from "./RangeCalendarState"; -export type CalendarCellOptions = BoxOptions & - Pick< - CalendarStateReturn, - "dateValue" | "isDisabled" | "currentMonth" | "isRangeCalendar" - > & - Partial< - Pick - > & { - date: Date; - }; - -export type CalendarCellHTMLProps = BoxHTMLProps; - -export type CalendarCellProps = CalendarCellOptions & CalendarCellHTMLProps; - export const useCalendarCell = createHook< CalendarCellOptions, CalendarCellHTMLProps @@ -97,3 +82,18 @@ const getCalendarCellProps = (options: CalendarCellOptions) => { "aria-selected": ariaAttr(isSelected), }; }; + +export type CalendarCellOptions = { + date: Date; +} & Pick< + CalendarStateReturn, + "dateValue" | "isDisabled" | "currentMonth" | "isRangeCalendar" +> & + Partial< + Pick + > & + BoxOptions; + +export type CalendarCellHTMLProps = BoxHTMLProps; + +export type CalendarCellProps = CalendarCellOptions & CalendarCellHTMLProps; diff --git a/src/calendar/CalendarCellButton.ts b/src/calendar/CalendarCellButton.ts index ed906431f..79fc93d4b 100644 --- a/src/calendar/CalendarCellButton.ts +++ b/src/calendar/CalendarCellButton.ts @@ -16,29 +16,6 @@ import { CALENDAR_CELL_BUTTON_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; import { RangeCalendarStateReturn } from "./RangeCalendarState"; -export type CalendarCellButtonOptions = ButtonOptions & - Pick< - CalendarStateReturn, - | "focusedDate" - | "selectDate" - | "setFocusedDate" - | "isDisabled" - | "month" - | "minDate" - | "maxDate" - | "dateValue" - | "isFocused" - | "isRangeCalendar" - > & - Partial> & { - date: Date; - }; - -export type CalendarCellButtonHTMLProps = ButtonHTMLProps; - -export type CalendarCellButtonProps = CalendarCellButtonOptions & - CalendarCellButtonHTMLProps; - export const useCalendarCellButton = createHook< CalendarCellButtonOptions, CalendarCellButtonHTMLProps @@ -162,3 +139,26 @@ export const CalendarCellButton = createComponent({ memo: true, useHook: useCalendarCellButton, }); + +export type CalendarCellButtonOptions = { + date: Date; +} & Pick< + CalendarStateReturn, + | "focusedDate" + | "selectDate" + | "setFocusedDate" + | "isDisabled" + | "month" + | "minDate" + | "maxDate" + | "dateValue" + | "isFocused" + | "isRangeCalendar" +> & + Partial> & + ButtonOptions; + +export type CalendarCellButtonHTMLProps = ButtonHTMLProps; + +export type CalendarCellButtonProps = CalendarCellButtonOptions & + CalendarCellButtonHTMLProps; diff --git a/src/calendar/CalendarGrid.ts b/src/calendar/CalendarGrid.ts index 42abca64d..64add462d 100644 --- a/src/calendar/CalendarGrid.ts +++ b/src/calendar/CalendarGrid.ts @@ -15,32 +15,6 @@ import { CALENDAR_GRID_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; import { RangeCalendarStateReturn } from "./RangeCalendarState"; -export type CalendarGridOptions = BoxOptions & - Pick< - CalendarStateReturn, - | "calendarId" - | "isReadOnly" - | "isDisabled" - | "setFocused" - | "selectFocusedDate" - | "focusPreviousYear" - | "focusPreviousMonth" - | "focusNextYear" - | "focusNextMonth" - | "focusEndOfMonth" - | "focusStartOfMonth" - | "focusNextDay" - | "focusPreviousDay" - | "focusNextWeek" - | "focusPreviousWeek" - | "isRangeCalendar" - > & - Partial>; - -export type CalendarGridHTMLProps = BoxHTMLProps; - -export type CalendarGridProps = CalendarGridOptions & CalendarGridHTMLProps; - export const useCalendarGrid = createHook< CalendarGridOptions, CalendarGridHTMLProps @@ -145,3 +119,29 @@ export const CalendarGrid = createComponent({ memo: true, useHook: useCalendarGrid, }); + +export type CalendarGridOptions = Pick< + CalendarStateReturn, + | "calendarId" + | "isReadOnly" + | "isDisabled" + | "setFocused" + | "selectFocusedDate" + | "focusPreviousYear" + | "focusPreviousMonth" + | "focusNextYear" + | "focusNextMonth" + | "focusEndOfMonth" + | "focusStartOfMonth" + | "focusNextDay" + | "focusPreviousDay" + | "focusNextWeek" + | "focusPreviousWeek" + | "isRangeCalendar" +> & + Partial> & + BoxOptions; + +export type CalendarGridHTMLProps = BoxHTMLProps; + +export type CalendarGridProps = CalendarGridOptions & CalendarGridHTMLProps; diff --git a/src/calendar/CalendarHeader.ts b/src/calendar/CalendarHeader.ts index 7463e6f90..ca05bca0f 100644 --- a/src/calendar/CalendarHeader.ts +++ b/src/calendar/CalendarHeader.ts @@ -6,16 +6,6 @@ import { CALENDAR_HEADER_KEYS } from "./__keys"; import { DateTimeFormatOpts } from "../utils/types"; import { CalendarStateReturn } from "./CalendarState"; -export type CalendarHeaderOptions = BoxOptions & - Pick & { - format?: DateTimeFormatOpts; - }; - -export type CalendarHeaderHTMLProps = BoxHTMLProps; - -export type CalendarHeaderProps = CalendarHeaderOptions & - CalendarHeaderHTMLProps; - export const useCalendarHeader = createHook< CalendarHeaderOptions, CalendarHeaderHTMLProps @@ -42,3 +32,13 @@ export const CalendarHeader = createComponent({ memo: true, useHook: useCalendarHeader, }); + +export type CalendarHeaderOptions = { + format?: DateTimeFormatOpts; +} & Pick & + BoxOptions; + +export type CalendarHeaderHTMLProps = BoxHTMLProps; + +export type CalendarHeaderProps = CalendarHeaderOptions & + CalendarHeaderHTMLProps; diff --git a/src/calendar/CalendarState.ts b/src/calendar/CalendarState.ts index 340be77e6..2c06f565c 100644 --- a/src/calendar/CalendarState.ts +++ b/src/calendar/CalendarState.ts @@ -33,21 +33,9 @@ import { announce } from "../utils/LiveAnnouncer"; import { isInvalidDateRange, parseDate, stringifyDate } from "../utils"; import { useWeekStart, useWeekDays, generateDaysInMonthArray } from "./helpers"; -export interface CalendarInitialState - extends ValueBase, - RangeValueBase, - InputBase { - /** - * Whether the element should receive focus on render. - */ - autoFocus?: boolean; - /** - * Id for the calendar grid - */ - id?: string; -} - -export function useCalendarState(props: CalendarInitialState = {}) { +export function useCalendarState( + props: CalendarInitialState = {}, +): CalendarStateReturn { const { value: initialDate, defaultValue: defaultValueProp, @@ -214,4 +202,154 @@ export function useCalendarState(props: CalendarInitialState = {}) { }; } -export type CalendarStateReturn = ReturnType; +export type CalendarState = { + /** + * Id for the Calendar Header + */ + calendarId: string | undefined; + /** + * Selected Date value + */ + dateValue: Date; + /** + * Minimum allowed Date value + */ + minDate: Date | undefined; + /** + * Maximum allowed Date value + */ + maxDate: Date | undefined; + /** + * Month of the current date value + */ + month: number; + /** + * Year of the current date value + */ + year: number; + /** + * Start of the week for the current date value + */ + weekStart: number; + /** + * Generated week days for CalendarWeekTitle based on weekStart + */ + weekDays: { + title: string; + abbr: string; + }[]; + /** + * Generated days in the current month + */ + daysInMonth: Date[][]; + /** + * `true` if the calendar is disabled + */ + isDisabled: boolean; + /** + * `true` if the calendar is focused + */ + isFocused: boolean; + /** + * `true` if the calendar is only readonly + */ + isReadOnly: boolean; + /** + * Month of the current Date + */ + currentMonth: Date; + /** + * Date value that is currently focused + */ + focusedDate: Date; + /** + * `true` if the calendar is used as RangeCalendar + */ + isRangeCalendar: boolean; +}; + +export type CalendarActions = { + /** + * Sets `isFocused` + */ + setFocused: React.Dispatch>; + /** + * Sets `currentMonth` + */ + setCurrentMonth: React.Dispatch>; + /** + * Sets `focusedDate` + */ + setFocusedDate: React.Dispatch>; + /** + * Sets `dateValue` + */ + setDateValue: (value: Date) => void; + /** + * Focus the cell of the specified date + */ + focusCell: (value: Date) => void; + /** + * Focus the cell next to the current date + */ + focusNextDay: () => void; + /** + * Focus the cell prev to the current date + */ + focusPreviousDay: () => void; + /** + * Focus the cell one week next to the current date + */ + focusNextWeek: () => void; + /** + * Focus the cell one week prev to the current date + */ + focusPreviousWeek: () => void; + /** + * Focus the cell one month next to the current date + */ + focusNextMonth: () => void; + /** + * Focus the cell one month prev to the current date + */ + focusPreviousMonth: () => void; + /** + * Focus the cell of the first day of the month + */ + focusStartOfMonth: () => void; + /** + * Focus the cell of the last day of the month + */ + focusEndOfMonth: () => void; + /** + * Focus the cell of the date one year from the current date + */ + focusNextYear: () => void; + /** + * Focus the cell of the date one year before the current date + */ + focusPreviousYear: () => void; + /** + * Selects the `focusedDate` + */ + selectFocusedDate: () => void; + /** + * sets `dateValue` + */ + selectDate: (value: Date) => void; +}; + +export type CalendarInitialState = ValueBase & + RangeValueBase & + InputBase & { + /** + * Whether the element should receive focus on render. + */ + autoFocus?: boolean; + /** + * Id for the calendar grid + */ + id?: string; + }; + +export type CalendarStateReturn = CalendarState & CalendarActions; diff --git a/src/calendar/CalendarWeekTitle.ts b/src/calendar/CalendarWeekTitle.ts index e24d5fe5e..b42645383 100644 --- a/src/calendar/CalendarWeekTitle.ts +++ b/src/calendar/CalendarWeekTitle.ts @@ -4,16 +4,6 @@ import { createComponent, createHook } from "reakit-system"; import { CALENDAR_WEEK_TITLE_KEYS } from "./__keys"; import { CalendarStateReturn } from "./CalendarState"; -export type CalendarWeekTitleOptions = BoxOptions & - Pick & { - dayIndex: number; - }; - -export type CalendarWeekTitleHTMLProps = BoxHTMLProps; - -export type CalendarWeekTitleProps = CalendarWeekTitleOptions & - CalendarWeekTitleHTMLProps; - export const useCalendarWeekTitle = createHook< CalendarWeekTitleOptions, CalendarWeekTitleHTMLProps @@ -35,3 +25,13 @@ export const CalendarWeekTitle = createComponent({ memo: true, useHook: useCalendarWeekTitle, }); + +export type CalendarWeekTitleOptions = { + dayIndex: number; +} & Pick & + BoxOptions; + +export type CalendarWeekTitleHTMLProps = BoxHTMLProps; + +export type CalendarWeekTitleProps = CalendarWeekTitleOptions & + CalendarWeekTitleHTMLProps; diff --git a/src/calendar/RangeCalendarState.ts b/src/calendar/RangeCalendarState.ts index aca461f16..98999a05e 100644 --- a/src/calendar/RangeCalendarState.ts +++ b/src/calendar/RangeCalendarState.ts @@ -13,22 +13,11 @@ import { RangeValueBase } from "../utils/types"; import { announce } from "../utils/LiveAnnouncer"; import { useCalendarState } from "./CalendarState"; import { parseRangeDate, stringifyDate } from "../utils"; +import { CalendarActions, CalendarState } from "./CalendarState"; -export interface RangeCalendarInitialState - extends ValueBase>, - RangeValueBase, - InputBase { - /** - * Whether the element should receive focus on render. - */ - autoFocus?: boolean; - /** - * Id for the calendar grid - */ - id?: string; -} - -export function useRangeCalendarState(props: RangeCalendarInitialState = {}) { +export function useRangeCalendarState( + props: RangeCalendarInitialState = {}, +): RangeCalendarStateReturn { const { value: initialDate, defaultValue: defaultValueProp, @@ -118,4 +107,33 @@ export function useRangeCalendarState(props: RangeCalendarInitialState = {}) { }; } -export type RangeCalendarStateReturn = ReturnType; +export type RangeCalendarState = CalendarState & { + dateRangeValue: RangeValue | null; + anchorDate: Date | null; + highlightedRange: RangeValue | null; + isRangeCalendar: boolean; +}; + +export type RangeCalendarActions = CalendarActions & { + setDateRangeValue: React.Dispatch>>; + setAnchorDate: React.Dispatch>; + selectDate: (date: Date) => void; + selectFocusedDate: () => void; + highlightDate: (date: Date) => void; +}; + +export type RangeCalendarInitialState = ValueBase> & + RangeValueBase & + InputBase & { + /** + * Whether the element should receive focus on render. + */ + autoFocus?: boolean; + /** + * Id for the calendar grid + */ + id?: string; + }; + +export type RangeCalendarStateReturn = RangeCalendarState & + RangeCalendarActions; diff --git a/src/calendar/helpers/useWeekStart.ts b/src/calendar/helpers/useWeekStart.ts index 449503353..e4ea8ceca 100644 --- a/src/calendar/helpers/useWeekStart.ts +++ b/src/calendar/helpers/useWeekStart.ts @@ -7,7 +7,7 @@ import { useLocale } from "@react-aria/i18n"; // Data from https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/weekData.json // Locales starting on Sunday have been removed for compression. -const data = { +const data: Record = { "001": 1, AD: 1, AE: 6, @@ -107,7 +107,7 @@ export function useWeekStart() { return data[region] || 0; } -function useRegion() { +function useRegion(): string { const { locale } = useLocale(); // If the Intl.Locale API is available, use it to get the region for the locale. diff --git a/yarn.lock b/yarn.lock index b14b18a18..59d1e102a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2839,6 +2839,24 @@ dependencies: "@babel/runtime" "^7.10.2" +"@textlint/ast-node-types@^4.0.0", "@textlint/ast-node-types@^4.3.4": + version "4.3.4" + resolved "https://registry.yarnpkg.com/@textlint/ast-node-types/-/ast-node-types-4.3.4.tgz#f6596c45c32c85dc06915c3077bb7686033efd32" + integrity sha512-Grq+vJuNH7HCa278eFeiqJvowrD+onMCoG2ctLyoN+fXYIQGIr1/8fo8AcIg+VM16Kga+N6Y1UWNOWPd8j1nFg== + +"@textlint/markdown-to-ast@^6.2.5": + version "6.2.5" + resolved "https://registry.yarnpkg.com/@textlint/markdown-to-ast/-/markdown-to-ast-6.2.5.tgz#b39d806520ff6507440c3e1d4242b9ec2a6086d0" + integrity sha512-9vlQbylGjnnRGev3yt9ntNy6I9FQH3p+MkbijybKnwobK/msoAX9sThDHOMbGM24PsUHxcDjktDlj2vHN/pwDA== + dependencies: + "@textlint/ast-node-types" "^4.3.4" + debug "^4.1.1" + remark-frontmatter "^1.2.0" + remark-parse "^5.0.0" + structured-source "^3.0.2" + traverse "^0.6.6" + unified "^6.1.6" + "@ts-morph/common@~0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.6.0.tgz#cbd4ee57c5ef971511b9c5778e0bb8eb27de4783" @@ -4000,6 +4018,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-to-markdown@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ast-to-markdown/-/ast-to-markdown-1.0.0.tgz#3073c3e15ec1a768404ca458f26a9f03e1e93d70" + integrity sha512-wMCSU5MK+LsnSdaVE1XS42bCpuKXbmEYjdcmEjyr9fgIeUcjnU90GVkf3AXPuzLXzNrII+s7lWvfIgglFreUtg== + ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" @@ -4105,6 +4128,13 @@ axios@^0.18.1: follow-redirects "1.5.10" is-buffer "^2.0.2" +axios@^0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca" + integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw== + dependencies: + follow-redirects "^1.10.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -4613,6 +4643,11 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= +boundary@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/boundary/-/boundary-1.0.1.tgz#4d67dc2602c0cc16dd9bce7ebf87e948290f5812" + integrity sha1-TWfcJgLAzBbdm85+v4fpSCkPWBI= + boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -5121,6 +5156,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +character-entities-html4@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125" + integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g== + character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" @@ -5396,7 +5436,7 @@ codesandbox-import-utils@^2.2.1: istextorbinary "^2.2.1" lz-string "^1.4.4" -codesandbox@^2.1.10: +codesandbox@^2.1.10, codesandbox@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/codesandbox/-/codesandbox-2.2.1.tgz#c09b26cf6844f3dff4718fac832beee493f6c2ff" integrity sha512-TOQVhLFlUYazflpnRyVO966sO4Avr2IyfUZn+TYad5WNM1v2WCkAS8ApC4+XNfXC11LGchxwG5MVnVfFlCWlbQ== @@ -6324,7 +6364,7 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: +debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -7632,7 +7672,7 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fault@^1.0.2: +fault@^1.0.1, fault@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== @@ -7884,6 +7924,11 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" +follow-redirects@^1.10.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -8747,7 +8792,7 @@ has-yarn@^2.1.0: resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== -has@^1.0.3: +has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -9365,6 +9410,11 @@ is-alphabetical@1.0.4, is-alphabetical@^1.0.0: resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== +is-alphanumeric@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" + integrity sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ= + is-alphanumerical@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" @@ -9397,7 +9447,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.0.2, is-buffer@^1.1.5: +is-buffer@^1.0.2, is-buffer@^1.1.4, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -11035,6 +11085,11 @@ loglevelnext@^1.0.1: es6-symbol "^3.1.1" object.assign "^4.1.0" +longest-streak@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" + integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -11195,6 +11250,22 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +markdown-table@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" + integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== + +markdown-to-ast@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/markdown-to-ast/-/markdown-to-ast-6.0.3.tgz#c939442fee0e2074975cd7049ce8103d7be8f021" + integrity sha512-P4YX5PTcFY0Bg5oWGRJ4o9Wq7TGqapO71zBKIjhnrqeEFzKk7srHtIYgaQAA8eofi/4EucDF3O3dJ/BUIi3FTA== + dependencies: + "@textlint/ast-node-types" "^4.0.0" + debug "^2.1.3" + remark "^7.0.1" + structured-source "^3.0.2" + traverse "^0.6.6" + markdown-to-jsx@^6.11.4: version "6.11.4" resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz#b4528b1ab668aef7fe61c1535c27e837819392c5" @@ -11213,6 +11284,11 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== +md-node-inject@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/md-node-inject/-/md-node-inject-1.0.1.tgz#2ceb36a6ad777c09c4a9b531f1398f8a0d765480" + integrity sha512-7ckd6AS/9KngfCUiakWJd8IUm8VLyCbrRhjIP9QFzNKACDKvvFk6f3YVfyMDvZa8GBu99bCkro/YVPGzDUY4/w== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -11229,6 +11305,13 @@ mdast-squeeze-paragraphs@^4.0.0: dependencies: unist-util-remove "^2.0.0" +mdast-util-compact@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz#d531bb7667b5123abf20859be086c4d06c894593" + integrity sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg== + dependencies: + unist-util-visit "^1.1.0" + mdast-util-definitions@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-2.0.1.tgz#2c931d8665a96670639f17f98e32c3afcfee25f3" @@ -12403,7 +12486,7 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-entities@^1.1.2: +parse-entities@^1.0.2, parse-entities@^1.1.0, parse-entities@^1.1.2: version "1.2.2" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== @@ -13895,6 +13978,14 @@ remark-footnotes@2.0.0: resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== +remark-frontmatter@^1.2.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/remark-frontmatter/-/remark-frontmatter-1.3.3.tgz#67ec63c89da5a84bb793ecec166e11b4eb47af10" + integrity sha512-fM5eZPBvu2pVNoq3ZPW22q+5Ativ1oLozq2qYt9I2oNyxiUd/tDl0iLLntEVAegpZIslPWg1brhcP1VsaSVUag== + dependencies: + fault "^1.0.1" + xtend "^4.0.1" + remark-mdx@1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.18.tgz#d8c76017c95824cc7fb853bb2759add8ba0cf319" @@ -13931,6 +14022,49 @@ remark-parse@8.0.3: vfile-location "^3.0.0" xtend "^4.0.1" +remark-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-3.0.1.tgz#1b9f841a44d8f4fbf2246850265459a4eb354c80" + integrity sha1-G5+EGkTY9PvyJGhQJlRZpOs1TIA= + dependencies: + collapse-white-space "^1.0.2" + has "^1.0.1" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.0.2" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + +remark-parse@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" + integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + remark-slug@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-6.0.0.tgz#2b54a14a7b50407a5e462ac2f376022cce263e2c" @@ -13947,6 +14081,35 @@ remark-squeeze-paragraphs@4.0.0: dependencies: mdast-squeeze-paragraphs "^4.0.0" +remark-stringify@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-3.0.1.tgz#79242bebe0a752081b5809516fa0c06edec069cf" + integrity sha1-eSQr6+CnUggbWAlRb6DAbt7Aac8= + dependencies: + ccount "^1.0.0" + is-alphanumeric "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + longest-streak "^2.0.1" + markdown-escapes "^1.0.0" + markdown-table "^1.1.0" + mdast-util-compact "^1.0.0" + parse-entities "^1.0.2" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + stringify-entities "^1.0.1" + unherit "^1.0.4" + xtend "^4.0.1" + +remark@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-7.0.1.tgz#a5de4dacfabf0f60a49826ef24c479807f904bfb" + integrity sha1-pd5NrPq/D2CkmCbvJMR5gH+QS/s= + dependencies: + remark-parse "^3.0.0" + remark-stringify "^3.0.0" + unified "^6.0.0" + remote-origin-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/remote-origin-url/-/remote-origin-url-0.4.0.tgz#4d3e2902f34e2d37d1c263d87710b77eb4086a30" @@ -15026,6 +15189,16 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-entities@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7" + integrity sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A== + dependencies: + character-entities-html4 "^1.0.0" + character-entities-legacy "^1.0.0" + is-alphanumerical "^1.0.0" + is-hexadecimal "^1.0.0" + stringify-object@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" @@ -15085,6 +15258,11 @@ strip-bom@^4.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== +strip-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" + integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -15124,6 +15302,13 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +structured-source@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/structured-source/-/structured-source-3.0.2.tgz#dd802425e0f53dc4a6e7aca3752901a1ccda7af5" + integrity sha1-3YAkJeD1PcSm56yjdSkBoczaevU= + dependencies: + boundary "^1.0.1" + style-loader@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" @@ -15520,6 +15705,11 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" +traverse@^0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -15588,10 +15778,10 @@ ts-jest@26.4.3: semver "7.x" yargs-parser "20.x" -ts-morph@8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-8.1.2.tgz#f0bee6be6fbd8c3174ac5d6c0423a035e36c2bbd" - integrity sha512-5w4TzmMzECrBunIku1T6/Y0Y2IJ9sHT6hAlfF59WugXnsq1dv6DSioA+s6LgUiswxjgaJgZndOKgu8BrLcYjKw== +ts-morph@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-8.2.0.tgz#41d83cd501cbd897eb029ac489d6d5b927555c57" + integrity sha512-NHHWu+7I2/AOZiTni5w3f+xCfIxrkzPCcQbTGa81Yk3pr23a4h9xLLEE6tIGuYIubWjkjr9QVC3ITqgmA5touQ== dependencies: "@dsherret/to-absolute-glob" "^2.0.2" "@ts-morph/common" "~0.6.0" @@ -15748,16 +15938,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@4.0.5: +typescript@4.0.5, typescript@~4.0.2: version "4.0.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== -typescript@~4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" - integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg== - uglify-js@^3.1.4: version "3.11.2" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.11.2.tgz#9f50325544273c27b20e586def140e7726c525ea" @@ -15816,6 +16001,18 @@ unified@9.2.0: trough "^1.0.0" vfile "^4.0.0" +unified@^6.0.0, unified@^6.1.6: + version "6.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" + integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^2.0.0" + x-is-string "^0.1.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -15869,6 +16066,11 @@ unist-util-generated@^1.0.0: resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.5.tgz#1e903e68467931ebfaea386dae9ea253628acd42" integrity sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw== +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + unist-util-is@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.0.2.tgz#c7d1341188aa9ce5b3cff538958de9895f14a5de" @@ -15879,6 +16081,13 @@ unist-util-position@^3.0.0: resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== +unist-util-remove-position@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" + integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== + dependencies: + unist-util-visit "^1.1.0" + unist-util-remove-position@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" @@ -15893,6 +16102,11 @@ unist-util-remove@^2.0.0: dependencies: unist-util-is "^4.0.0" +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + unist-util-stringify-position@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" @@ -15900,6 +16114,13 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" +unist-util-visit-parents@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" + integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== + dependencies: + unist-util-is "^3.0.0" + unist-util-visit-parents@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.0.tgz#4dd262fb9dcfe44f297d53e882fc6ff3421173d5" @@ -15917,6 +16138,13 @@ unist-util-visit@2.0.3, unist-util-visit@^2.0.0: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" +unist-util-visit@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" + integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== + dependencies: + unist-util-visit-parents "^2.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -16182,11 +16410,23 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vfile-location@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" + integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== + vfile-location@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.1.0.tgz#81cd8a04b0ac935185f4fce16f270503fc2f692f" integrity sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g== +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + vfile-message@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" @@ -16195,6 +16435,16 @@ vfile-message@^2.0.0: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" +vfile@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" + integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== + dependencies: + is-buffer "^1.1.4" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + vfile@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.0.tgz#26c78ac92eb70816b01d4565e003b7e65a2a0e01" @@ -16508,6 +16758,11 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" From 7c93870b8a5876c8c5152bbc075d83b30bc2e4df Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 2 Dec 2020 18:51:22 +0530 Subject: [PATCH 11/12] =?UTF-8?q?docs(composition):=20=F0=9F=93=9D=20=20up?= =?UTF-8?q?date=20composition=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/accordion.md | 22 ++-- docs/breadcrumb.md | 2 +- docs/calendar.md | 14 +-- docs/datepicker.md | 14 +-- docs/drawer.md | 8 +- docs/meter.md | 16 +-- docs/number-input.md | 39 ++++--- docs/pagination.md | 4 +- docs/picker-base.md | 8 +- docs/progress.md | 8 +- docs/segment.md | 2 +- docs/select.md | 9 +- docs/slider.md | 12 +-- docs/timepicker.md | 12 +-- docs/toast.md | 4 +- scripts/utils/inject-composition.js | 13 +++ yarn.lock | 156 ++++++++++++---------------- 17 files changed, 168 insertions(+), 175 deletions(-) diff --git a/docs/accordion.md b/docs/accordion.md index 31de0149a..9e001df8f 100644 --- a/docs/accordion.md +++ b/docs/accordion.md @@ -3,7 +3,7 @@ Accessible Accordion component. It follows the [WAI-ARIA Accordion Pattern](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion). -[Accordion Example Live Demo](https://codesandbox.io/s/qvgg2) +[Accordion Example Live Demo](https://codesandbox.io/s/h7wdn) ## Props @@ -11,11 +11,11 @@ Accessible Accordion component. It follows the ### `useAccordionState` -- **`allowMultiple`** false | undefined Allow to open multiple - accordion items - **`manual`** boolean Whether the accodion selection should be manual. - **`allowToggle`** boolean Allow to toggle accordion items +- **`allowMultiple`** false | undefined Allow to open multiple + accordion items - **`baseId`** string ID that will serve as a base for all the items IDs. - **`unstable_virtual`** โš ๏ธ @@ -139,7 +139,7 @@ form elements. In this case, only `aria-disabled` will be set. - **`items`** Item[] Lists all the composite items with their `id`, DOM `ref`, `disabled` state and `groupId` if any. This state is automatically updated when `registerItem` and `unregisterItem` are called. -- **`move`** (id: string | null) => void Moves focus to a given +- **`move`** (id: StringOrNull) => void Moves focus to a given item ID. - **`setCurrentId`** (value: @@ -174,8 +174,8 @@ form elements. In this case, only `aria-disabled` will be set. items - **`selectedId`** string | null | undefined The current selected accordion's `id`. -- **`selectedIds`** (string | null)[] | undefined The current - selected accordion's `id`. +- **`selectedIds`** StringOrNull[] | undefined The current selected + accordion's `id`. - **`items`** Item[] Lists all the composite items with their `id`, DOM `ref`, `disabled` state and `groupId` if any. This state is automatically updated when `registerItem` and `unregisterItem` are called. @@ -251,17 +251,17 @@ form elements. In this case, only `aria-disabled` will be set. Moves focus to the item below. - **`manual`** boolean Whether the accodion selection should be manual. +- **`allowToggle`** boolean Allow to toggle accordion items - **`allowMultiple`** boolean Allow to open multiple accordion items - **`selectedId`** string | null | undefined The current selected accordion's `id`. -- **`allowToggle`** boolean Allow to toggle accordion items -- **`selectedIds`** (string | null)[] | undefined The current - selected accordion's `id`. +- **`selectedIds`** StringOrNull[] | undefined The current selected + accordion's `id`. - **`panels`** Item[] Lists all the panels. -- **`select`** (id: string | null) => void Moves into and +- **`select`** (id: StringOrNull) => void Moves into and selects an accordion by its `id`. -- **`unSelect`** (id: string | null) => void Moves into and +- **`unSelect`** (id: StringOrNull) => void Moves into and unSelects an accordion by its `id` if it's already selected. diff --git a/docs/breadcrumb.md b/docs/breadcrumb.md index 59711184b..bc7e137d8 100644 --- a/docs/breadcrumb.md +++ b/docs/breadcrumb.md @@ -32,7 +32,7 @@ No props to show ## Composition - BreadcrumbLink uses [useLink](./link.md) -- Breadcrumbs uses [useBox](https://reakit.io/docs/box) +- Breadcrumbs uses [useRole](https://reakit.io/docs/role) ## Example diff --git a/docs/calendar.md b/docs/calendar.md index f6d7810ae..af0872acd 100644 --- a/docs/calendar.md +++ b/docs/calendar.md @@ -2,9 +2,9 @@ Accessible `Calendar` component. -[RangeCalendar - Open On Sandbox](https://codesandbox.io/s/khdp2) +[RangeCalendar - Open On Sandbox](https://codesandbox.io/s/86dqv) -[Calendar - Open On Sandbox](https://codesandbox.io/s/pmtcs) +[Calendar - Open On Sandbox](https://codesandbox.io/s/qte2l) ## Props @@ -186,13 +186,13 @@ form elements. In this case, only `aria-disabled` will be set. ## Composition -- Calendar uses [useBox](https://reakit.io/docs/box) +- Calendar uses [useRole](https://reakit.io/docs/role) - CalendarButton uses [useButton](https://reakit.io/docs/button) -- CalendarCell uses [useBox](https://reakit.io/docs/box) +- CalendarCell uses [useRole](https://reakit.io/docs/role) - CalendarCellButton uses [useButton](https://reakit.io/docs/button) -- CalendarGrid uses [useBox](https://reakit.io/docs/box) -- CalendarHeader uses [useBox](https://reakit.io/docs/box) -- CalendarWeekTitle uses [useBox](https://reakit.io/docs/box) +- CalendarGrid uses [useRole](https://reakit.io/docs/role) +- CalendarHeader uses [useRole](https://reakit.io/docs/role) +- CalendarWeekTitle uses [useRole](https://reakit.io/docs/role) ## Example diff --git a/docs/datepicker.md b/docs/datepicker.md index 25218cc06..3fd94d69b 100644 --- a/docs/datepicker.md +++ b/docs/datepicker.md @@ -2,9 +2,9 @@ Accessible `DatePicker` component. -[DatePicker - Open On Sandbox](https://codesandbox.io/s/ixpqy) +[RangeDatePicker - Open On Sandbox](https://codesandbox.io/s/cq9ql) -[RangeDatePicker - Open On Sandbox](https://codesandbox.io/s/wlu79) +[DatePicker - Open On Sandbox](https://codesandbox.io/s/4j912) ## Props @@ -180,11 +180,11 @@ form elements. In this case, only `aria-disabled` will be set. ## Composition -- DatePicker uses [usePickerBase](undefined) -- DatePickerContent uses [usePickerBaseContent](undefined) -- DatePickerSegment uses [useSegment](undefined) -- DatePickerSegmentField uses [useSegmentField](undefined) -- DatePickerTrigger uses [usePickerBaseTrigger](undefined) +- DatePicker uses [usePickerBase](./picker-base.md) +- DatePickerContent uses [usePickerBaseContent](./picker-base.md) +- DatePickerSegment uses [useSegment](./segment.md) +- DatePickerSegmentField uses [useSegmentField](./segment.md) +- DatePickerTrigger uses [usePickerBaseTrigger](./picker-base.md) ## Example diff --git a/docs/drawer.md b/docs/drawer.md index 3860ed818..9668a32cd 100644 --- a/docs/drawer.md +++ b/docs/drawer.md @@ -2,7 +2,7 @@ Accessible `Drawer` component. -[Drawer - Open On Sandbox](https://codesandbox.io/s/96zk3) +[Drawer - Open On Sandbox](https://codesandbox.io/s/c13ec) ## Props @@ -62,14 +62,14 @@ Accessible `Drawer` component. ## Composition -- Drawer uses [useDialog](undefined) -- DrawerCloseButton uses [useDialogDisclosure](undefined) +- Drawer uses [useDialog](https://reakit.io/docs/dialog/) +- DrawerCloseButton uses [useDialogDisclosure](https://reakit.io/docs/dialog/) ## Example ```js import React from "react"; -import { css } from "@emotion/css"; +import { css } from "emotion"; import { Drawer, diff --git a/docs/meter.md b/docs/meter.md index cd219ee66..e97a64b02 100644 --- a/docs/meter.md +++ b/docs/meter.md @@ -2,7 +2,7 @@ Accessible `Meter` component. -[Meter - Open On Sandbox](https://codesandbox.io/s/vyipe) +[Meter - Open On Sandbox](https://codesandbox.io/s/n9f9q) ## Props @@ -12,21 +12,21 @@ Accessible `Meter` component. - **`value`** number The `value` of the meter indicator. -If `undefined`/`not valid` the meter bar will be equal to `min` + If `undefined`/`not valid` the meter bar will be equal to `min` - **`min`** number The minimum value of the meter - **`max`** number The maximum value of the meter - **`low`** number The higher limit of min range. -Defaults to `min`. + Defaults to `min`. - **`optimum`** number The lower limit of max range. -Defaults to `median of low & high`. + Defaults to `median of low & high`. - **`high`** number The lower limit of max range. -Defaults to `max`. + Defaults to `max`. ### `Meter` @@ -35,7 +35,7 @@ Defaults to `max`. - **`value`** number The `value` of the meter indicator. -If `undefined`/`not valid` the meter bar will be equal to `min` + If `undefined`/`not valid` the meter bar will be equal to `min` - **`min`** number The minimum value of the meter - **`max`** number The maximum value of the meter @@ -46,13 +46,13 @@ If `undefined`/`not valid` the meter bar will be equal to `min` ## Composition -- Meter uses [useBox](https://reakit.io/docs/box) +- Meter uses [useRole](https://reakit.io/docs/role) ## Example ```js import * as React from "react"; -import { css, keyframes } from "@emotion/css"; +import { css, keyframes } from "emotion"; import { Meter, useMeterState } from "renderless-components"; diff --git a/docs/number-input.md b/docs/number-input.md index 9aac8840d..fcd3776c8 100644 --- a/docs/number-input.md +++ b/docs/number-input.md @@ -2,7 +2,7 @@ Accessible `NumberInput` component. -[NumberInput - Open On Sandbox](https://codesandbox.io/s/siflz) +[NumberInput - Open On Sandbox](https://codesandbox.io/s/ybuxv) ## Props @@ -13,15 +13,16 @@ Accessible `NumberInput` component. - **`value`** string | number The value of the counter. Should be less than `max` and greater than `min` -If no value, initial value is set to `""` + If no value, initial value is set to `""` - **`keepWithinRange`** boolean This controls the value update behavior in general. -- If `true` and you use the stepper or up/down arrow keys, the value will not - exceed the `max` or go lower than `min` + - If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + + - If `false`, the value will be allowed to go out of range. -- If `false`, the value will be allowed to go out of range. - **`min`** number The minimum value of the counter - **`max`** number The maximum value of the counter - **`step`** number The step used to increment or decrement the @@ -29,7 +30,8 @@ If no value, initial value is set to `""` - **`precision`** number The number of decimal points used to round the value -If no precision, initial value is from the decimal places from value/step - `0` + If no precision, initial value is from the decimal places from value/step - + `0` - **`defaultValue`** string | number | undefined The initial value of the counter. Should be less than `max` and greater than `min` @@ -59,14 +61,15 @@ value will change based on mouse wheel - **`keepWithinRange`** boolean This controls the value update behavior in general. -- If `true` and you use the stepper or up/down arrow keys, the value will not - exceed the `max` or go lower than `min` + - If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + + - If `false`, the value will be allowed to go out of range. -- If `false`, the value will be allowed to go out of range. - **`value`** string | number The value of the counter. Should be less than `max` and greater than `min` -If no value, initial value is set to `""` + If no value, initial value is set to `""` - **`min`** number The minimum value of the counter - **`max`** number The maximum value of the counter @@ -100,10 +103,11 @@ form elements. In this case, only `aria-disabled` will be set. - **`keepWithinRange`** boolean This controls the value update behavior in general. -- If `true` and you use the stepper or up/down arrow keys, the value will not - exceed the `max` or go lower than `min` + - If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + + - If `false`, the value will be allowed to go out of range. -- If `false`, the value will be allowed to go out of range. - **`isAtMin`** boolean Truw, if value is equal to min. - **`focusInput`** () => void Focus input if focus input on value change is `true` @@ -126,10 +130,11 @@ form elements. In this case, only `aria-disabled` will be set. - **`keepWithinRange`** boolean This controls the value update behavior in general. -- If `true` and you use the stepper or up/down arrow keys, the value will not - exceed the `max` or go lower than `min` + - If `true` and you use the stepper or up/down arrow keys, the value will not + exceed the `max` or go lower than `min` + + - If `false`, the value will be allowed to go out of range. -- If `false`, the value will be allowed to go out of range. - **`isAtMax`** boolean True, if value is equal to max. - **`focusInput`** () => void Focus input if focus input on value change is `true` @@ -142,7 +147,7 @@ form elements. In this case, only `aria-disabled` will be set. ## Composition -- NumberInput uses [useInput](undefined) +- NumberInput uses [useInput](https://reakit.io/docs/input/) - NumberInputDecrementButton uses [useButton](https://reakit.io/docs/button) - NumberInputIncrementButton uses [useButton](https://reakit.io/docs/button) diff --git a/docs/pagination.md b/docs/pagination.md index b6680583e..ea94b631f 100644 --- a/docs/pagination.md +++ b/docs/pagination.md @@ -2,7 +2,7 @@ Accessible `Pagination` component. -[Pagination - Open On Sandbox](https://codesandbox.io/s/ugo4e) +[Pagination - Open On Sandbox](https://codesandbox.io/s/jp1fn) ## Props @@ -71,7 +71,7 @@ Accessible `Pagination` component. ## Composition -- Pagination uses [useBox](https://reakit.io/docs/box) +- Pagination uses [useRole](https://reakit.io/docs/role) - PaginationButton uses [useButton](https://reakit.io/docs/button) ## Example diff --git a/docs/picker-base.md b/docs/picker-base.md index fa5773fd9..8c869b56c 100644 --- a/docs/picker-base.md +++ b/docs/picker-base.md @@ -2,7 +2,7 @@ Accessible `PickerBase` component. -[PickerBase - Open On Sandbox](https://codesandbox.io/s/neryg) +[PickerBase - Open On Sandbox](https://codesandbox.io/s/rsuxm) ## Props @@ -96,9 +96,9 @@ form elements. In this case, only `aria-disabled` will be set. ## Composition -- PickerBase uses [useBox](https://reakit.io/docs/box) -- PickerBaseContent uses [usePopover](undefined) -- PickerBaseTrigger uses [usePopoverDisclosure](undefined) +- PickerBase uses [useRole](https://reakit.io/docs/role) +- PickerBaseContent uses [usePopover](https://reakit.io/docs/popover/) +- PickerBaseTrigger uses [usePopoverDisclosure](https://reakit.io/docs/popover/) ## Example diff --git a/docs/progress.md b/docs/progress.md index 92b5be9e7..3753ae603 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -12,7 +12,7 @@ Accessible `Progress` component. - **`value`** number | null The `value` of the progress indicator. -If `null` the progress bar will be in `indeterminate` state + If `null` the progress bar will be in `indeterminate` state - **`min`** number The minimum value of the progress - **`max`** number The maximum value of the @@ -24,7 +24,7 @@ If `null` the progress bar will be in `indeterminate` state - **`value`** number | null The `value` of the progress indicator. -If `null` the progress bar will be in `indeterminate` state + If `null` the progress bar will be in `indeterminate` state - **`min`** number The minimum value of the progress - **`max`** number The maximum value of the @@ -34,14 +34,14 @@ If `null` the progress bar will be in `indeterminate` state ## Composition -- Progress uses [useBox](https://reakit.io/docs/box) +- Progress uses [useRole](https://reakit.io/docs/role) ## Example ```js import * as React from "react"; import { Button } from "reakit"; -import { css, keyframes } from "@emotion/css"; +import { css, keyframes } from "emotion"; import { cx, isNull, Progress, useProgressState } from "renderless-components"; diff --git a/docs/segment.md b/docs/segment.md index c3d1b2f55..72ebe6bfa 100644 --- a/docs/segment.md +++ b/docs/segment.md @@ -2,7 +2,7 @@ Accessible `Segment` component. -[Segment - Open On Sandbox](https://codesandbox.io/s/xiccb) +[Segment - Open On Sandbox](https://codesandbox.io/s/pddby) ## Props diff --git a/docs/select.md b/docs/select.md index 70e361fb6..8e1d8f244 100644 --- a/docs/select.md +++ b/docs/select.md @@ -2,7 +2,7 @@ Accessible `Select` component. -[Select - Open On Sandbox](https://codesandbox.io/s/tcnxl) +[Select - Open On Sandbox](https://codesandbox.io/s/hrtki) ## Props @@ -715,11 +715,12 @@ if `modal` is `false`. ## Composition -- Select uses [usePopoverDisclosure](undefined) +- Select uses [usePopoverDisclosure](https://reakit.io/docs/popover/) - SelectItem uses [useCompositeItem](https://reakit.io/docs/composite) - SelectList uses [useComposite](https://reakit.io/docs/composite) -- SelectOption uses [useSelectItem](undefined) -- SelectPopover uses [useSelectList](undefined) and [usePopover](undefined) +- SelectOption uses [useSelectItem](./select.md) +- SelectPopover uses [useSelectList](./select.md) and + [usePopover](https://reakit.io/docs/popover/) ## Example diff --git a/docs/slider.md b/docs/slider.md index 4604fae88..52599e8c0 100644 --- a/docs/slider.md +++ b/docs/slider.md @@ -2,7 +2,7 @@ Accessible `Slider` component. -[Slider - Open On Sandbox](https://codesandbox.io/s/d0mp9) +[Slider - Open On Sandbox](https://codesandbox.io/s/s20jt) ## Props @@ -12,7 +12,7 @@ Accessible `Slider` component. - **`values`** number[] The `value` of the slider indicator. -If `undefined`/`not valid` the slider bar will be the optimum of min & max + If `undefined`/`not valid` the slider bar will be the optimum of min & max - **`min`** number The minimum value of the slider - **`max`** number The maximum value of the slider @@ -111,7 +111,7 @@ If `undefined`/`not valid` the slider bar will be the optimum of min & max - **`values`** number[] The `value` of the slider indicator. -If `undefined`/`not valid` the slider bar will be the optimum of min & max + If `undefined`/`not valid` the slider bar will be the optimum of min & max - **`isDisabled`** boolean If `true`, the slider will be disabled - **`orientation`** "horizontal" | "vertical" @@ -143,9 +143,9 @@ If `undefined`/`not valid` the slider bar will be the optimum of min & max ## Composition - SliderInput uses [unstable_useId](https://reakit.io/docs/id) and - [useInput](undefined) -- SliderThumb uses [useBox](https://reakit.io/docs/box) -- SliderTrack uses [useBox](https://reakit.io/docs/box) + [useInput](https://reakit.io/docs/input/) +- SliderThumb uses [useRole](https://reakit.io/docs/role) +- SliderTrack uses [useRole](https://reakit.io/docs/role) ## Example diff --git a/docs/timepicker.md b/docs/timepicker.md index 49f78b344..d6238b726 100644 --- a/docs/timepicker.md +++ b/docs/timepicker.md @@ -2,7 +2,7 @@ Accessible `TimePicker` component. -[TimePicker - Open On Sandbox](https://codesandbox.io/s/mdhu9) +[TimePicker - Open On Sandbox](https://codesandbox.io/s/5k3uo) ## Props @@ -724,14 +724,14 @@ form elements. In this case, only `aria-disabled` will be set. ## Composition -- TimePicker uses [usePickerBase](undefined) +- TimePicker uses [usePickerBase](./picker-base.md) - TimePickerColumn uses [useComposite](https://reakit.io/docs/composite) - TimePickerColumnValue uses [useButton](https://reakit.io/docs/button) and [useCompositeItem](https://reakit.io/docs/composite) -- TimePickerContent uses [usePickerBaseContent](undefined) -- TimePickerSegment uses [useSegment](undefined) -- TimePickerSegmentField uses [useSegmentField](undefined) -- TimePickerTrigger uses [usePickerBaseTrigger](undefined) +- TimePickerContent uses [usePickerBaseContent](./picker-base.md) +- TimePickerSegment uses [useSegment](./segment.md) +- TimePickerSegmentField uses [useSegmentField](./segment.md) +- TimePickerTrigger uses [usePickerBaseTrigger](./picker-base.md) ## Example diff --git a/docs/toast.md b/docs/toast.md index bd3ae6be5..73785c275 100644 --- a/docs/toast.md +++ b/docs/toast.md @@ -2,9 +2,9 @@ Accessible `Toast` component. -[Toast CSS Animated - Open On Sandbox](https://codesandbox.io/s/ze954) +[Toast - Open On Sandbox](https://codesandbox.io/s/fkpd6) -[Toast - Open On Sandbox](https://codesandbox.io/s/clz0m) +[Toast CSS Animated - Open On Sandbox](https://codesandbox.io/s/dwkcp) ## Example diff --git a/scripts/utils/inject-composition.js b/scripts/utils/inject-composition.js index 8ff4a0d47..d9552f6fe 100644 --- a/scripts/utils/inject-composition.js +++ b/scripts/utils/inject-composition.js @@ -63,11 +63,24 @@ function getMarkdown(compose) { useComposite: "https://reakit.io/docs/composite", useCompositeItem: "https://reakit.io/docs/composite", unstable_useId: "https://reakit.io/docs/id", + useDialog: "https://reakit.io/docs/dialog/", + useDialogDisclosure: "https://reakit.io/docs/dialog/", useDisclosureContent: "https://reakit.io/docs/disclosure", + usePopover: "https://reakit.io/docs/popover/", + usePopoverDisclosure: "https://reakit.io/docs/popover/", useButton: "https://reakit.io/docs/button", useBox: "https://reakit.io/docs/box", + useRole: "https://reakit.io/docs/role", + useInput: "https://reakit.io/docs/input/", useClickable: "https://reakit.io/docs/clickable", useLink: "./link.md", + usePickerBase: "./picker-base.md", + usePickerBaseContent: "./picker-base.md", + usePickerBaseTrigger: "./picker-base.md", + useSegment: "./segment.md", + useSegmentField: "./segment.md", + useSelectItem: "./select.md", + useSelectList: "./select.md", }; const formatter = new Intl.ListFormat("en", { diff --git a/yarn.lock b/yarn.lock index ca776a0af..31ba68c55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1122,11 +1122,7 @@ dependencies: regenerator-runtime "^0.13.4" -<<<<<<< HEAD -"@babel/runtime@^7.12.1": -======= -"@babel/runtime@^7.12.5": ->>>>>>> master +"@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== @@ -1632,6 +1628,13 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/create-cache-key-function@^26.5.0": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-26.6.2.tgz#04cf439207a4fd12418d8aee551cddc86f9ac5f5" + integrity sha512-LgEuqU1f/7WEIPYqwLPIvvHuc1sB6gMVbT6zWhin3txYUNYK/kGQrC1F2WR4gR34YlI9bBtViTm5z98RqVZAaw== + dependencies: + "@jest/types" "^26.6.2" + "@jest/environment@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" @@ -3013,10 +3016,10 @@ "@babel/runtime" "^7.12.5" "@testing-library/dom" "^7.27.1" -"@testing-library/user-event@12.2.2": - version "12.2.2" - resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-12.2.2.tgz#22d0047da745289335240f523dfe74c889ec96cb" - integrity sha512-mTYL9LrwiSeyorStUOMuRGQDn1ca40tIhuv//o/K3lY8wBEp+9Im90MFVx5i3u7zCPmavn3uWZs/10chsbI8Tg== +"@testing-library/user-event@12.1.10": + version "12.1.10" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-12.1.10.tgz#e043ef5aa10e4b3e56b434e383d2fbfef1fcfb7f" + integrity sha512-StlNdKHp2Rpb7yrny/5/CGpz8bR3jLa1Ge59ODGU6TmAhkrxSpvR6tCD1gaMFkkjEUWkmmye8BaXsZPcaiJ6Ug== dependencies: "@babel/runtime" "^7.10.2" @@ -3497,61 +3500,61 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.1.tgz#b362abe0ee478a6c6d06c14552a6497f0b480769" - integrity sha512-d7LeQ7dbUrIv5YVFNzGgaW3IQKMmnmKFneRWagRlGYOSfLJVaRbj/FrBNOBC1a3tVO+TgNq1GbHvRtg1kwL0FQ== +"@typescript-eslint/eslint-plugin@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.6.0.tgz#210cd538bb703f883aff81d3996961f5dba31fdb" + integrity sha512-1+419X+Ynijytr1iWI+/IcX/kJryc78YNpdaXR1aRO1sU3bC0vZrIAF1tIX7rudVI84W7o7M4zo5p1aVt70fAg== dependencies: - "@typescript-eslint/experimental-utils" "4.8.1" - "@typescript-eslint/scope-manager" "4.8.1" + "@typescript-eslint/experimental-utils" "4.6.0" + "@typescript-eslint/scope-manager" "4.6.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.1.tgz#27275c20fa4336df99ebcf6195f7d7aa7aa9f22d" - integrity sha512-WigyLn144R3+lGATXW4nNcDJ9JlTkG8YdBWHkDlN0lC3gUGtDi7Pe3h5GPvFKMcRz8KbZpm9FJV9NTW8CpRHpg== +"@typescript-eslint/experimental-utils@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.0.tgz#f750aef4dd8e5970b5c36084f0a5ca2f0db309a4" + integrity sha512-pnh6Beh2/4xjJVNL+keP49DFHk3orDHHFylSp3WEjtgW3y1U+6l+jNnJrGlbs6qhAz5z96aFmmbUyKhunXKvKw== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.8.1" - "@typescript-eslint/types" "4.8.1" - "@typescript-eslint/typescript-estree" "4.8.1" + "@typescript-eslint/scope-manager" "4.6.0" + "@typescript-eslint/types" "4.6.0" + "@typescript-eslint/typescript-estree" "4.6.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.8.1.tgz#4fe2fbdbb67485bafc4320b3ae91e34efe1219d1" - integrity sha512-QND8XSVetATHK9y2Ltc/XBl5Ro7Y62YuZKnPEwnNPB8E379fDsvzJ1dMJ46fg/VOmk0hXhatc+GXs5MaXuL5Uw== +"@typescript-eslint/parser@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.6.0.tgz#7e9ff7df2f21d5c8f65f17add3b99eeeec33199d" + integrity sha512-Dj6NJxBhbdbPSZ5DYsQqpR32MwujF772F2H3VojWU6iT4AqL4BKuoNWOPFCoSZvCcADDvQjDpa6OLDAaiZPz2Q== dependencies: - "@typescript-eslint/scope-manager" "4.8.1" - "@typescript-eslint/types" "4.8.1" - "@typescript-eslint/typescript-estree" "4.8.1" + "@typescript-eslint/scope-manager" "4.6.0" + "@typescript-eslint/types" "4.6.0" + "@typescript-eslint/typescript-estree" "4.6.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.8.1.tgz#e343c475f8f1d15801b546cb17d7f309b768fdce" - integrity sha512-r0iUOc41KFFbZdPAdCS4K1mXivnSZqXS5D9oW+iykQsRlTbQRfuFRSW20xKDdYiaCoH+SkSLeIF484g3kWzwOQ== +"@typescript-eslint/scope-manager@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.6.0.tgz#b7d8b57fe354047a72dfb31881d9643092838662" + integrity sha512-uZx5KvStXP/lwrMrfQQwDNvh2ppiXzz5TmyTVHb+5TfZ3sUP7U1onlz3pjoWrK9konRyFe1czyxObWTly27Ang== dependencies: - "@typescript-eslint/types" "4.8.1" - "@typescript-eslint/visitor-keys" "4.8.1" + "@typescript-eslint/types" "4.6.0" + "@typescript-eslint/visitor-keys" "4.6.0" -"@typescript-eslint/types@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.8.1.tgz#23829c73c5fc6f4fcd5346a7780b274f72fee222" - integrity sha512-ave2a18x2Y25q5K05K/U3JQIe2Av4+TNi/2YuzyaXLAsDx6UZkz1boZ7nR/N6Wwae2PpudTZmHFXqu7faXfHmA== +"@typescript-eslint/types@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.6.0.tgz#157ca925637fd53c193c6bf226a6c02b752dde2f" + integrity sha512-5FAgjqH68SfFG4UTtIFv+rqYJg0nLjfkjD0iv+5O27a0xEeNZ5rZNDvFGZDizlCD1Ifj7MAbSW2DPMrf0E9zjA== -"@typescript-eslint/typescript-estree@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.1.tgz#7307e3f2c9e95df7daa8dc0a34b8c43b7ec0dd32" - integrity sha512-bJ6Fn/6tW2g7WIkCWh3QRlaSU7CdUUK52shx36/J7T5oTQzANvi6raoTsbwGM11+7eBbeem8hCCKbyvAc0X3sQ== +"@typescript-eslint/typescript-estree@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.0.tgz#85bd98dcc8280511cfc5b2ce7b03a9ffa1732b08" + integrity sha512-s4Z9qubMrAo/tw0CbN0IN4AtfwuehGXVZM0CHNMdfYMGBDhPdwTEpBrecwhP7dRJu6d9tT9ECYNaWDHvlFSngA== dependencies: - "@typescript-eslint/types" "4.8.1" - "@typescript-eslint/visitor-keys" "4.8.1" + "@typescript-eslint/types" "4.6.0" + "@typescript-eslint/visitor-keys" "4.6.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -3559,12 +3562,12 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.1.tgz#794f68ee292d1b2e3aa9690ebedfcb3a8c90e3c3" - integrity sha512-3nrwXFdEYALQh/zW8rFwP4QltqsanCDz4CwWMPiIZmwlk9GlvBeueEIbq05SEq4ganqM0g9nh02xXgv5XI3PeQ== +"@typescript-eslint/visitor-keys@4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.0.tgz#fb05d6393891b0a089b243fc8f9fb8039383d5da" + integrity sha512-38Aa9Ztl0XyFPVzmutHXqDMCu15Xx8yKvUo38Gu3GhsuckCh3StPI5t2WIO9LHEsOH7MLmlGfKUisU8eW1Sjhg== dependencies: - "@typescript-eslint/types" "4.8.1" + "@typescript-eslint/types" "4.6.0" eslint-visitor-keys "^2.0.0" "@vivaxy/git@^4.1.1": @@ -7933,11 +7936,7 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -<<<<<<< HEAD -fault@^1.0.1, fault@^1.0.2: -======= -fault@^1.0.0, fault@^1.0.2: ->>>>>>> master +fault@^1.0.0, fault@^1.0.1, fault@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== @@ -13154,16 +13153,12 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -<<<<<<< HEAD pify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== -pinkie-promise@^2.0.0: -======= pinkie-promise@^2.0.0, pinkie-promise@^2.0.1: ->>>>>>> master version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= @@ -14411,7 +14406,6 @@ remark-footnotes@2.0.0: resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== -<<<<<<< HEAD remark-frontmatter@^1.2.0: version "1.3.3" resolved "https://registry.yarnpkg.com/remark-frontmatter/-/remark-frontmatter-1.3.3.tgz#67ec63c89da5a84bb793ecec166e11b4eb47af10" @@ -14420,16 +14414,10 @@ remark-frontmatter@^1.2.0: fault "^1.0.1" xtend "^4.0.1" -remark-mdx@1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.18.tgz#d8c76017c95824cc7fb853bb2759add8ba0cf319" - integrity sha512-xNhjv4kJZ8L6RV68yK8fQ6XWlvSIFOE5VPmM7wMKSwkvwBu6tlUJy0gRF2WiZ4fPPOj6jpqlVB9QakipvZuEqg== -======= remark-mdx@1.6.21: version "1.6.21" resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.21.tgz#0c1a7e042e50938ff89ad8dd7e8e219d4b0404ce" integrity sha512-IGb3l46a6NFi62egT+WXeTT3T8wYTunmPCEGTfDO6oRAfuss9VAb/3InVCKKGXXoiNi0mTuplI0EFusdCLGk3A== ->>>>>>> master dependencies: "@babel/core" "7.11.6" "@babel/helper-plugin-utils" "7.10.4" @@ -16147,12 +16135,6 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" -<<<<<<< HEAD -traverse@^0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= -======= trash@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/trash/-/trash-6.1.1.tgz#8fb863421b31f32571f2650b53534934d5e63025" @@ -16167,7 +16149,11 @@ trash@^6.1.1: p-try "^2.2.0" uuid "^3.3.2" xdg-trashdir "^2.1.1" ->>>>>>> master + +traverse@^0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= tree-kill@^1.2.2: version "1.2.2" @@ -16224,11 +16210,12 @@ ts-essentials@^2.0.3: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== -ts-jest@26.4.4: - version "26.4.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.4.tgz#61f13fb21ab400853c532270e52cc0ed7e502c49" - integrity sha512-3lFWKbLxJm34QxyVNNCgXX1u4o/RV0myvA2y2Bxm46iGIjKlaY0own9gIckbjZJPn+WaJEnfPPJ20HHGpoq4yg== +ts-jest@26.4.3: + version "26.4.3" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.3.tgz#d153a616033e7ec8544b97ddbe2638cbe38d53db" + integrity sha512-pFDkOKFGY+nL9v5pkhm+BIFpoAuno96ff7GMnIYr/3L6slFOS365SI0fGEVYx2RKGji5M2elxhWjDMPVcOCdSw== dependencies: + "@jest/create-cache-key-function" "^26.5.0" "@types/jest" "26.x" bs-logger "0.x" buffer-from "1.x" @@ -16241,11 +16228,7 @@ ts-jest@26.4.4: semver "7.x" yargs-parser "20.x" -<<<<<<< HEAD ts-morph@^8.2.0: -======= -ts-morph@8.2.0: ->>>>>>> master version "8.2.0" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-8.2.0.tgz#41d83cd501cbd897eb029ac489d6d5b927555c57" integrity sha512-NHHWu+7I2/AOZiTni5w3f+xCfIxrkzPCcQbTGa81Yk3pr23a4h9xLLEE6tIGuYIubWjkjr9QVC3ITqgmA5touQ== @@ -16405,17 +16388,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -<<<<<<< HEAD typescript@4.0.5, typescript@~4.0.2: version "4.0.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== -======= -typescript@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9" - integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== ->>>>>>> master uglify-js@^3.1.4: version "3.11.2" @@ -17244,19 +17220,17 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== -<<<<<<< HEAD x-is-string@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= -======= + xdg-basedir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I= dependencies: os-homedir "^1.0.0" ->>>>>>> master xdg-basedir@^3.0.0: version "3.0.0" From 526a28b56ac44233d46de7979d09028cea0dcab3 Mon Sep 17 00:00:00 2001 From: Navin Date: Wed, 2 Dec 2020 19:03:30 +0530 Subject: [PATCH 12/12] =?UTF-8?q?build(utils):=20=F0=9F=92=9A=20=20fix=20t?= =?UTF-8?q?he=20build=20with=20utils=20&=20csb=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate-js.js | 2 +- scripts/transpile-ts.js | 1 + scripts/utils/inject-csb-links.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/generate-js.js b/scripts/generate-js.js index 8d6844c96..1ef9e2084 100644 --- a/scripts/generate-js.js +++ b/scripts/generate-js.js @@ -10,7 +10,7 @@ const { createFile, getDirectories, createDirectory, -} = require("./fs-utils"); +} = require("./utils/fs-utils"); const transpileTs = require("./transpile-ts"); // -> get all the component folders [accordion, breadcrumb...] diff --git a/scripts/transpile-ts.js b/scripts/transpile-ts.js index 8d7637f26..fffadd0c0 100644 --- a/scripts/transpile-ts.js +++ b/scripts/transpile-ts.js @@ -1,6 +1,7 @@ const ts = require("typescript"); const prettier = require("prettier/standalone"); const parserBabel = require("prettier/parser-babel"); + const prettierConfig = require("../.prettierrc.json"); module.exports = function transformTs(file) { diff --git a/scripts/utils/inject-csb-links.js b/scripts/utils/inject-csb-links.js index 6bb8bb1cf..ad8186da7 100644 --- a/scripts/utils/inject-csb-links.js +++ b/scripts/utils/inject-csb-links.js @@ -82,8 +82,8 @@ const getSandboxDefineLink = (files, extraDeps) => { ReactDOM.render(, rootElement); `, }, - "src/App.js": files.js && { content: files.js }, - "src/styles.css": files.css && { content: files.css }, + "src/App.js": files.js ? { content: files.js } : "", + "src/styles.css": files.css ? { content: files.css } : "", "src/Utils.component.js": files.utils && { content: files.utils, },