From 2e152666d38aea981407228848037f37fe721093 Mon Sep 17 00:00:00 2001 From: Fabien MARIE-LOUISE Date: Mon, 30 May 2022 19:22:41 +0200 Subject: [PATCH 01/52] feat(menu): add createMenuTriggerState primitive --- packages/menu/CHANGELOG.md | 0 packages/menu/LICENSE.md | 21 +++ packages/menu/README.md | 25 +++ packages/menu/dev/index.html | 14 ++ packages/menu/dev/index.tsx | 7 + packages/menu/dev/vite.config.ts | 3 + packages/menu/jest.config.cjs | 5 + packages/menu/package.json | 59 ++++++ packages/menu/src/createMenuTriggerState.ts | 68 +++++++ packages/menu/src/index.ts | 18 ++ packages/menu/tsconfig.json | 5 + packages/menu/tsup.config.ts | 3 + packages/menu/vite.config.ts | 3 + packages/types/src/index.ts | 1 + packages/types/src/selection.ts | 18 ++ pnpm-lock.yaml | 187 +++++++++++++++----- 16 files changed, 390 insertions(+), 47 deletions(-) create mode 100644 packages/menu/CHANGELOG.md create mode 100644 packages/menu/LICENSE.md create mode 100644 packages/menu/README.md create mode 100644 packages/menu/dev/index.html create mode 100644 packages/menu/dev/index.tsx create mode 100644 packages/menu/dev/vite.config.ts create mode 100644 packages/menu/jest.config.cjs create mode 100644 packages/menu/package.json create mode 100644 packages/menu/src/createMenuTriggerState.ts create mode 100644 packages/menu/src/index.ts create mode 100644 packages/menu/tsconfig.json create mode 100644 packages/menu/tsup.config.ts create mode 100644 packages/menu/vite.config.ts create mode 100644 packages/types/src/selection.ts diff --git a/packages/menu/CHANGELOG.md b/packages/menu/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/menu/LICENSE.md b/packages/menu/LICENSE.md new file mode 100644 index 0000000..4a0310d --- /dev/null +++ b/packages/menu/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Solid Aria Working Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/menu/README.md b/packages/menu/README.md new file mode 100644 index 0000000..ff843bd --- /dev/null +++ b/packages/menu/README.md @@ -0,0 +1,25 @@ +

+ Solid Aria - Menu +

+ +# @solid-aria/menu + +[![pnpm](https://img.shields.io/badge/maintained%20with-pnpm-cc00ff.svg?style=for-the-badge&logo=pnpm)](https://pnpm.io/) +[![turborepo](https://img.shields.io/badge/built%20with-turborepo-cc00ff.svg?style=for-the-badge&logo=turborepo)](https://turborepo.org/) +[![size](https://img.shields.io/bundlephobia/minzip/@solid-aria/menu?style=for-the-badge&label=size)](https://bundlephobia.com/package/@solid-aria/menu) +[![version](https://img.shields.io/npm/v/@solid-aria/menu?style=for-the-badge)](https://www.npmjs.com/package/@solid-aria/menu) +[![stage](https://img.shields.io/endpoint?style=for-the-badge&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-0.json)](https://github.com/solidjs-community/solid-aria#contribution-process) + +## Installation + +```bash +npm install @solid-aria/menu +# or +yarn add @solid-aria/menu +# or +pnpm add @solid-aria/menu +``` + +## Changelog + +All notable changes are described in the [CHANGELOG.md](./CHANGELOG.md) file. diff --git a/packages/menu/dev/index.html b/packages/menu/dev/index.html new file mode 100644 index 0000000..c3eddaf --- /dev/null +++ b/packages/menu/dev/index.html @@ -0,0 +1,14 @@ + + + + + + + Solid App + + + +
+ + + diff --git a/packages/menu/dev/index.tsx b/packages/menu/dev/index.tsx new file mode 100644 index 0000000..b80e4e2 --- /dev/null +++ b/packages/menu/dev/index.tsx @@ -0,0 +1,7 @@ +import { render } from "solid-js/web"; + +function App() { + return
Hello Solid Aria!
; +} + +render(() => , document.getElementById("root") as HTMLDivElement); diff --git a/packages/menu/dev/vite.config.ts b/packages/menu/dev/vite.config.ts new file mode 100644 index 0000000..2f3fe11 --- /dev/null +++ b/packages/menu/dev/vite.config.ts @@ -0,0 +1,3 @@ +import { viteConfig } from "../../../vite.config"; + +export default viteConfig; diff --git a/packages/menu/jest.config.cjs b/packages/menu/jest.config.cjs new file mode 100644 index 0000000..c68d815 --- /dev/null +++ b/packages/menu/jest.config.cjs @@ -0,0 +1,5 @@ +const baseJest = require("../../jest.config.cjs"); + +module.exports = { + ...baseJest +}; diff --git a/packages/menu/package.json b/packages/menu/package.json new file mode 100644 index 0000000..9f2b34d --- /dev/null +++ b/packages/menu/package.json @@ -0,0 +1,59 @@ +{ + "name": "@solid-aria/menu", + "version": "0.0.0", + "private": false, + "description": "Primitives for building accessible menu component.", + "keywords": [ + "solid", + "aria", + "headless", + "design", + "system", + "components" + ], + "homepage": "https://github.com/solidjs-community/solid-aria/tree/main/packages/menu#readme", + "bugs": { + "url": "https://github.com/solidjs-community/solid-aria/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/solidjs-community/solid-aria.git" + }, + "license": "MIT", + "author": "Fabien Marie-Louise ", + "contributors": [], + "sideEffects": false, + "type": "module", + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", + "dev": "vite serve dev --host", + "test": "jest --passWithNoTests", + "test:watch": "jest --watch --passWithNoTests", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@solid-aria/overlays": "workspace:^", + "@solid-aria/types": "workspace:^", + "@solid-aria/utils": "workspace:^" + }, + "peerDependencies": { + "@solid-primitives/utils": "^2.0.1", + "solid-js": "^1.4.3" + }, + "publishConfig": { + "access": "public" + }, + "primitive": { + "name": "menu", + "stage": 0, + "list": [], + "category": "" + } +} diff --git a/packages/menu/src/createMenuTriggerState.ts b/packages/menu/src/createMenuTriggerState.ts new file mode 100644 index 0000000..9539cec --- /dev/null +++ b/packages/menu/src/createMenuTriggerState.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2022 Solid Aria Working Group. + * MIT License + * + * Portions of this file are based on code from react-spectrum. + * Copyright 2020 Adobe. All rights reserved. + * + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { + createOverlayTriggerState, + CreateOverlayTriggerStateProps, + OverlayTriggerState +} from "@solid-aria/overlays"; +import { FocusStrategy } from "@solid-aria/types"; +import { Accessor, createSignal } from "solid-js"; + +export interface MenuTriggerState extends OverlayTriggerState { + /** + * Controls which item will be auto focused when the menu opens. + */ + readonly focusStrategy: Accessor; + + /** + * Opens the menu. + */ + open: (focusStrategy?: FocusStrategy) => void; + + /** + * Toggles the menu. + */ + toggle: (focusStrategy?: FocusStrategy) => void; +} + +/** + * Manages state for a menu trigger. Tracks whether the menu is currently open, + * and controls which item will receive focus when it opens. + */ +export function createMenuTriggerState(props: CreateOverlayTriggerStateProps): MenuTriggerState { + const overlayTriggerState = createOverlayTriggerState(props); + const [focusStrategy, setFocusStrategy] = createSignal(); + + const open = (focusStrategy?: FocusStrategy) => { + setFocusStrategy(focusStrategy); + overlayTriggerState.open(); + }; + + const toggle = (focusStrategy?: FocusStrategy) => { + setFocusStrategy(focusStrategy); + overlayTriggerState.toggle(); + }; + + return { + focusStrategy, + ...overlayTriggerState, + // override the ones from `overlayTriggerState` + open, + toggle + }; +} diff --git a/packages/menu/src/index.ts b/packages/menu/src/index.ts new file mode 100644 index 0000000..64fba8d --- /dev/null +++ b/packages/menu/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2022 Solid Aria Working Group. + * MIT License + * + * Portions of this file are based on code from react-spectrum. + * Copyright 2020 Adobe. All rights reserved. + * + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from "./createMenuTriggerState"; diff --git a/packages/menu/tsconfig.json b/packages/menu/tsconfig.json new file mode 100644 index 0000000..b5b011c --- /dev/null +++ b/packages/menu/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "include": ["./src", "./test", "./dev"], + "exclude": ["node_modules", "./dist"] +} diff --git a/packages/menu/tsup.config.ts b/packages/menu/tsup.config.ts new file mode 100644 index 0000000..9097772 --- /dev/null +++ b/packages/menu/tsup.config.ts @@ -0,0 +1,3 @@ +import defaultConfig from "../../tsup.config"; + +export default defaultConfig; diff --git a/packages/menu/vite.config.ts b/packages/menu/vite.config.ts new file mode 100644 index 0000000..c06c04b --- /dev/null +++ b/packages/menu/vite.config.ts @@ -0,0 +1,3 @@ +import { viteConfig } from "../../vite.config"; + +export default viteConfig; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index cd7db06..75e746f 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -24,3 +24,4 @@ export * from "./label"; export * from "./locale"; export * from "./orientation"; export * from "./polymorphic"; +export * from "./selection"; diff --git a/packages/types/src/selection.ts b/packages/types/src/selection.ts new file mode 100644 index 0000000..d61b83d --- /dev/null +++ b/packages/types/src/selection.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2022 Solid Aria Working Group. + * MIT License + * + * Portions of this file are based on code from react-spectrum. + * Copyright 2020 Adobe. All rights reserved. + * + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export type FocusStrategy = "first" | "last"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a559329..ab58404 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.3 +lockfileVersion: 5.4 importers: @@ -55,28 +55,28 @@ importers: '@changesets/cli': 2.22.0 '@commitlint/cli': 16.2.3 '@commitlint/config-conventional': 16.2.1 - '@commitlint/cz-commitlint': 16.2.3_commitizen@4.2.4+inquirer@8.2.2 + '@commitlint/cz-commitlint': 16.2.3_m5bc3bhc52kndzzuhyfjcrpiqq '@solid-primitives/props': 2.1.2_solid-js@1.4.3 '@solid-primitives/refs': 0.2.0_solid-js@1.4.3 '@solid-primitives/utils': 2.0.3_solid-js@1.4.3 '@testing-library/dom': 8.13.0 '@testing-library/jest-dom': 5.16.4 - '@testing-library/user-event': 14.1.1_@testing-library+dom@8.13.0 + '@testing-library/user-event': 14.1.1_tlwynutqiyp5mns3woioasuxnq '@types/jest': 27.4.1 '@types/node': 17.0.25 '@types/testing-library__jest-dom': 5.14.3 - '@typescript-eslint/eslint-plugin': 5.20.0_f056fa114ebe497ef05a90154e3337ef - '@typescript-eslint/parser': 5.20.0_eslint@8.12.0+typescript@4.6.3 + '@typescript-eslint/eslint-plugin': 5.20.0_6blpuekoxzex54c2saku4mzx54 + '@typescript-eslint/parser': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re babel-preset-solid: 1.3.13_@babel+core@7.17.9 commitizen: 4.2.4 eslint: 8.12.0 eslint-config-prettier: 8.5.0_eslint@8.12.0 - eslint-import-resolver-typescript: 2.7.1_6727bad621c6c338589cdfead936b843 - eslint-plugin-import: 2.26.0_eslint@8.12.0 + eslint-import-resolver-typescript: 2.7.1_m4t3vvrby3btqwe437vnsnvyim + eslint-plugin-import: 2.26.0_45iswicuh2jf6uw5f4otiu26ni eslint-plugin-jsx-a11y: 6.5.1_eslint@8.12.0 - eslint-plugin-prettier: 4.0.0_f2c91d0f54113167d2bd9214a5ab5a36 + eslint-plugin-prettier: 4.0.0_6ler2d2uceywpuv5sikklk22gy eslint-plugin-simple-import-sort: 7.0.0_eslint@8.12.0 - eslint-plugin-solid: 0.4.6_eslint@8.12.0+typescript@4.6.3 + eslint-plugin-solid: 0.4.6_thk3xo4exzjr5rl6cnexo7v6re husky: 7.0.4 inquirer: 8.2.2 jest: 27.5.1 @@ -87,7 +87,7 @@ importers: solid-js: 1.4.3 solid-testing-library: 0.3.0_solid-js@1.4.3 sort-package-json: 1.55.0 - ts-jest: 27.1.4_1a7a295883fc72da5121c34ec472fa0c + ts-jest: 27.1.4_dj5cswed7rznuujbynhmi4x2bq tsup: 5.12.6_typescript@4.6.3 turbo: 1.2.4 typescript: 4.6.3 @@ -212,6 +212,16 @@ importers: '@solid-aria/types': link:../types '@solid-aria/utils': link:../utils + packages/menu: + specifiers: + '@solid-aria/overlays': workspace:^ + '@solid-aria/types': workspace:^ + '@solid-aria/utils': workspace:^ + dependencies: + '@solid-aria/overlays': link:../overlays + '@solid-aria/types': link:../types + '@solid-aria/utils': link:../utils + packages/overlays: specifiers: '@solid-aria/button': workspace:^ @@ -327,7 +337,7 @@ importers: '@solid-primitives/utils': ^2.0.1 dependencies: '@solid-aria/types': link:../types - '@solid-primitives/utils': 2.0.3_solid-js@1.4.3 + '@solid-primitives/utils': 2.0.3 packages/visually-hidden: specifiers: @@ -635,6 +645,8 @@ packages: resolution: {integrity: sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==} engines: {node: '>=6.0.0'} hasBin: true + dependencies: + '@babel/types': 7.18.2 dev: true /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.17.12_@babel+core@7.17.9: @@ -1776,7 +1788,7 @@ packages: dev: true optional: true - /@commitlint/cz-commitlint/16.2.3_commitizen@4.2.4+inquirer@8.2.2: + /@commitlint/cz-commitlint/16.2.3_m5bc3bhc52kndzzuhyfjcrpiqq: resolution: {integrity: sha512-G9rRnBJ/5te7RiOzp7EdqII9rQYvtsfsqwMxcoK4B7l0Rc57nFCOlf0e4Bn70E4aOsLeMzNe+PvVVrEsPStEHg==} engines: {node: '>=v12'} peerDependencies: @@ -1852,7 +1864,7 @@ packages: '@types/node': 17.0.25 chalk: 4.1.2 cosmiconfig: 7.0.1 - cosmiconfig-typescript-loader: 2.0.1_de7c86b0cde507c63a0402da5b982bd3 + cosmiconfig-typescript-loader: 2.0.1_3z6inmgn4ud4moqealnfxgbl2m lodash: 4.17.21 resolve-from: 5.0.0 typescript: 4.6.3 @@ -1864,6 +1876,7 @@ packages: /@commitlint/load/17.0.0: resolution: {integrity: sha512-XaiHF4yWQOPAI0O6wXvk+NYLtJn/Xb7jgZEeKd4C1ZWd7vR7u8z5h0PkWxSr0uLZGQsElGxv3fiZ32C5+q6M8w==} engines: {node: '>=v14'} + requiresBuild: true dependencies: '@commitlint/config-validator': 17.0.0 '@commitlint/execute-rule': 17.0.0 @@ -1872,7 +1885,7 @@ packages: '@types/node': 17.0.25 chalk: 4.1.2 cosmiconfig: 7.0.1 - cosmiconfig-typescript-loader: 2.0.1_7a0f9a5efe0d630f200da2ab59a10b64 + cosmiconfig-typescript-loader: 2.0.1_pihzuxx6bvrq6ianukvvtiilmq lodash: 4.17.21 resolve-from: 5.0.0 typescript: 4.7.2 @@ -2312,7 +2325,7 @@ packages: fastq: 1.13.0 dev: true - /@rollup/plugin-babel/5.3.1_@babel+core@7.17.9+rollup@2.73.0: + /@rollup/plugin-babel/5.3.1_qzlmjbpiggkjlpjf4nr7koycvm: resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} engines: {node: '>= 10.0.0'} peerDependencies: @@ -2421,12 +2434,19 @@ packages: solid-js: 1.4.3 dev: true + /@solid-primitives/utils/2.0.3: + resolution: {integrity: sha512-dIv339WSJZ8C50kcJ7Ys5aLPSs59+GMsSrtJ/bGnA38gkLgmKry1XIZJLAUVz/uiOiZ661GUJ+IMngsqG8u09g==} + peerDependencies: + solid-js: ^1.4.1 + dev: false + /@solid-primitives/utils/2.0.3_solid-js@1.4.3: resolution: {integrity: sha512-dIv339WSJZ8C50kcJ7Ys5aLPSs59+GMsSrtJ/bGnA38gkLgmKry1XIZJLAUVz/uiOiZ661GUJ+IMngsqG8u09g==} peerDependencies: solid-js: ^1.4.1 dependencies: solid-js: 1.4.3 + dev: true /@testing-library/dom/7.31.2: resolution: {integrity: sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==} @@ -2471,7 +2491,7 @@ packages: redent: 3.0.0 dev: true - /@testing-library/user-event/14.1.1_@testing-library+dom@8.13.0: + /@testing-library/user-event/14.1.1_tlwynutqiyp5mns3woioasuxnq: resolution: {integrity: sha512-XrjH/iEUqNl9lF2HX9YhPNV7Amntkcnpw0Bo1KkRzowNDcgSN9i0nm4Q8Oi5wupgdfPaJNMAWa61A+voD6Kmwg==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -2652,7 +2672,7 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin/5.20.0_f056fa114ebe497ef05a90154e3337ef: + /@typescript-eslint/eslint-plugin/5.20.0_6blpuekoxzex54c2saku4mzx54: resolution: {integrity: sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2663,10 +2683,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.20.0_eslint@8.12.0+typescript@4.6.3 + '@typescript-eslint/parser': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re '@typescript-eslint/scope-manager': 5.20.0 - '@typescript-eslint/type-utils': 5.20.0_eslint@8.12.0+typescript@4.6.3 - '@typescript-eslint/utils': 5.20.0_eslint@8.12.0+typescript@4.6.3 + '@typescript-eslint/type-utils': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re + '@typescript-eslint/utils': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re debug: 4.3.4 eslint: 8.12.0 functional-red-black-tree: 1.0.1 @@ -2679,7 +2699,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.20.0_eslint@8.12.0+typescript@4.6.3: + /@typescript-eslint/parser/5.20.0_thk3xo4exzjr5rl6cnexo7v6re: resolution: {integrity: sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2715,7 +2735,7 @@ packages: '@typescript-eslint/visitor-keys': 5.26.0 dev: true - /@typescript-eslint/type-utils/5.20.0_eslint@8.12.0+typescript@4.6.3: + /@typescript-eslint/type-utils/5.20.0_thk3xo4exzjr5rl6cnexo7v6re: resolution: {integrity: sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2725,7 +2745,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/utils': 5.20.0_eslint@8.12.0+typescript@4.6.3 + '@typescript-eslint/utils': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re debug: 4.3.4 eslint: 8.12.0 tsutils: 3.21.0_typescript@4.6.3 @@ -2786,7 +2806,7 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.20.0_eslint@8.12.0+typescript@4.6.3: + /@typescript-eslint/utils/5.20.0_thk3xo4exzjr5rl6cnexo7v6re: resolution: {integrity: sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2804,7 +2824,7 @@ packages: - typescript dev: true - /@typescript-eslint/utils/5.26.0_eslint@8.12.0+typescript@4.6.3: + /@typescript-eslint/utils/5.26.0_thk3xo4exzjr5rl6cnexo7v6re: resolution: {integrity: sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3627,7 +3647,7 @@ packages: requiresBuild: true dev: true - /cosmiconfig-typescript-loader/2.0.1_7a0f9a5efe0d630f200da2ab59a10b64: + /cosmiconfig-typescript-loader/2.0.1_3z6inmgn4ud4moqealnfxgbl2m: resolution: {integrity: sha512-B9s6sX/omXq7I6gC6+YgLmrBFMJhPWew7ty/X5Tuwtd2zOSgWaUdXjkuVwbe3qqcdETo60+1nSVMekq//LIXVA==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -3636,15 +3656,14 @@ packages: dependencies: '@types/node': 17.0.25 cosmiconfig: 7.0.1 - ts-node: 10.8.0_7a0f9a5efe0d630f200da2ab59a10b64 - typescript: 4.7.2 + ts-node: 10.8.0_3z6inmgn4ud4moqealnfxgbl2m + typescript: 4.6.3 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' dev: true - optional: true - /cosmiconfig-typescript-loader/2.0.1_de7c86b0cde507c63a0402da5b982bd3: + /cosmiconfig-typescript-loader/2.0.1_pihzuxx6bvrq6ianukvvtiilmq: resolution: {integrity: sha512-B9s6sX/omXq7I6gC6+YgLmrBFMJhPWew7ty/X5Tuwtd2zOSgWaUdXjkuVwbe3qqcdETo60+1nSVMekq//LIXVA==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -3653,12 +3672,13 @@ packages: dependencies: '@types/node': 17.0.25 cosmiconfig: 7.0.1 - ts-node: 10.8.0_de7c86b0cde507c63a0402da5b982bd3 - typescript: 4.6.3 + ts-node: 10.8.0_pihzuxx6bvrq6ianukvvtiilmq + typescript: 4.7.2 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' dev: true + optional: true /cosmiconfig/7.0.1: resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==} @@ -3778,12 +3798,22 @@ packages: /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.0.0 dev: true /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 dev: true @@ -4019,6 +4049,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [android] + requiresBuild: true dev: true optional: true @@ -4027,6 +4058,7 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [android] + requiresBuild: true dev: true optional: true @@ -4035,6 +4067,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [darwin] + requiresBuild: true dev: true optional: true @@ -4043,6 +4076,7 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [darwin] + requiresBuild: true dev: true optional: true @@ -4051,6 +4085,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [freebsd] + requiresBuild: true dev: true optional: true @@ -4059,6 +4094,7 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + requiresBuild: true dev: true optional: true @@ -4067,6 +4103,7 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [linux] + requiresBuild: true dev: true optional: true @@ -4075,6 +4112,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [linux] + requiresBuild: true dev: true optional: true @@ -4083,6 +4121,7 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [linux] + requiresBuild: true dev: true optional: true @@ -4091,6 +4130,7 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [linux] + requiresBuild: true dev: true optional: true @@ -4099,6 +4139,7 @@ packages: engines: {node: '>=12'} cpu: [mips64el] os: [linux] + requiresBuild: true dev: true optional: true @@ -4107,6 +4148,7 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [linux] + requiresBuild: true dev: true optional: true @@ -4115,6 +4157,7 @@ packages: engines: {node: '>=12'} cpu: [riscv64] os: [linux] + requiresBuild: true dev: true optional: true @@ -4123,6 +4166,7 @@ packages: engines: {node: '>=12'} cpu: [s390x] os: [linux] + requiresBuild: true dev: true optional: true @@ -4131,6 +4175,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [netbsd] + requiresBuild: true dev: true optional: true @@ -4139,6 +4184,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [openbsd] + requiresBuild: true dev: true optional: true @@ -4147,6 +4193,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [sunos] + requiresBuild: true dev: true optional: true @@ -4155,6 +4202,7 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [win32] + requiresBuild: true dev: true optional: true @@ -4163,6 +4211,7 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [win32] + requiresBuild: true dev: true optional: true @@ -4171,6 +4220,7 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [win32] + requiresBuild: true dev: true optional: true @@ -4249,9 +4299,11 @@ packages: dependencies: debug: 3.2.7 resolve: 1.22.0 + transitivePeerDependencies: + - supports-color dev: true - /eslint-import-resolver-typescript/2.7.1_6727bad621c6c338589cdfead936b843: + /eslint-import-resolver-typescript/2.7.1_m4t3vvrby3btqwe437vnsnvyim: resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} engines: {node: '>=4'} peerDependencies: @@ -4260,7 +4312,7 @@ packages: dependencies: debug: 4.3.4 eslint: 8.12.0 - eslint-plugin-import: 2.26.0_eslint@8.12.0 + eslint-plugin-import: 2.26.0_45iswicuh2jf6uw5f4otiu26ni glob: 7.2.3 is-glob: 4.0.3 resolve: 1.22.0 @@ -4269,27 +4321,51 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.3: + /eslint-module-utils/2.7.3_jbyz37hizqiddyo5guvrx6copq: resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true dependencies: + '@typescript-eslint/parser': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re debug: 3.2.7 + eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-typescript: 2.7.1_m4t3vvrby3btqwe437vnsnvyim find-up: 2.1.0 + transitivePeerDependencies: + - supports-color dev: true - /eslint-plugin-import/2.26.0_eslint@8.12.0: + /eslint-plugin-import/2.26.0_45iswicuh2jf6uw5f4otiu26ni: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: + '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true dependencies: + '@typescript-eslint/parser': 5.20.0_thk3xo4exzjr5rl6cnexo7v6re array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.12.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3 + eslint-module-utils: 2.7.3_jbyz37hizqiddyo5guvrx6copq has: 1.0.3 is-core-module: 2.9.0 is-glob: 4.0.3 @@ -4297,6 +4373,10 @@ packages: object.values: 1.1.5 resolve: 1.22.0 tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color dev: true /eslint-plugin-jsx-a11y/6.5.1_eslint@8.12.0: @@ -4320,7 +4400,7 @@ packages: minimatch: 3.1.2 dev: true - /eslint-plugin-prettier/4.0.0_f2c91d0f54113167d2bd9214a5ab5a36: + /eslint-plugin-prettier/4.0.0_6ler2d2uceywpuv5sikklk22gy: resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==} engines: {node: '>=6.0.0'} peerDependencies: @@ -4345,13 +4425,13 @@ packages: eslint: 8.12.0 dev: true - /eslint-plugin-solid/0.4.6_eslint@8.12.0+typescript@4.6.3: + /eslint-plugin-solid/0.4.6_thk3xo4exzjr5rl6cnexo7v6re: resolution: {integrity: sha512-XYF2Xoa73XEf7Q7n0tdHveTUWp6Kq0jkegnB3vvtMvP1cGJXgfbDOiN7X4TxpE9fj16NI63ruOnxXfIn4EsGUg==} engines: {node: '>=12.0.0'} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.26.0_eslint@8.12.0+typescript@4.6.3 + '@typescript-eslint/utils': 5.26.0_thk3xo4exzjr5rl6cnexo7v6re eslint: 8.12.0 is-html: 2.0.0 jsx-ast-utils: 3.3.0 @@ -4715,6 +4795,7 @@ packages: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + requiresBuild: true dev: true optional: true @@ -7052,7 +7133,7 @@ packages: '@babel/core': 7.17.9 '@babel/preset-env': 7.16.11_@babel+core@7.17.9 '@babel/preset-typescript': 7.16.7_@babel+core@7.17.9 - '@rollup/plugin-babel': 5.3.1_@babel+core@7.17.9+rollup@2.73.0 + '@rollup/plugin-babel': 5.3.1_qzlmjbpiggkjlpjf4nr7koycvm '@rollup/plugin-node-resolve': 13.3.0_rollup@2.73.0 babel-preset-solid: 1.3.13_@babel+core@7.17.9 colorette: 2.0.16 @@ -7678,7 +7759,7 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true - /ts-jest/27.1.4_1a7a295883fc72da5121c34ec472fa0c: + /ts-jest/27.1.4_dj5cswed7rznuujbynhmi4x2bq: resolution: {integrity: sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true @@ -7713,7 +7794,7 @@ packages: yargs-parser: 20.2.9 dev: true - /ts-node/10.8.0_7a0f9a5efe0d630f200da2ab59a10b64: + /ts-node/10.8.0_3z6inmgn4ud4moqealnfxgbl2m: resolution: {integrity: sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==} hasBin: true peerDependencies: @@ -7739,13 +7820,12 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.7.2 + typescript: 4.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true - optional: true - /ts-node/10.8.0_de7c86b0cde507c63a0402da5b982bd3: + /ts-node/10.8.0_pihzuxx6bvrq6ianukvvtiilmq: resolution: {integrity: sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==} hasBin: true peerDependencies: @@ -7771,10 +7851,11 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.6.3 + typescript: 4.7.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true + optional: true /ts-toolbelt/9.6.0: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} @@ -7854,6 +7935,7 @@ packages: resolution: {integrity: sha512-fIseb9faJZdrJ2LXJAMZmSI5hV5MbHiRKIEnwt6pqk9+8HcJnsz3Rfo7uSNH07Qo64moXyoDHa0YFj00PH2Aeg==} cpu: [x64] os: [darwin] + requiresBuild: true dev: true optional: true @@ -7861,6 +7943,7 @@ packages: resolution: {integrity: sha512-/iAKexDsoXLHeLpM71+MMHDL7x95++M1GSIVkME1MJyUwG0RMfjlciBG99ZCBlya39rJhc0ifSLhZVWUttTmJA==} cpu: [arm64] os: [darwin] + requiresBuild: true dev: true optional: true @@ -7868,6 +7951,7 @@ packages: resolution: {integrity: sha512-YULjq/JW8e2ax/McguL+yHmZxGdLXseKVIVWP1f2dhuF9ztAbGTaagdDnQ8atsqDO0gFsb3WiRo4+4X/NAbgvQ==} cpu: [x64] os: [freebsd] + requiresBuild: true dev: true optional: true @@ -7875,6 +7959,7 @@ packages: resolution: {integrity: sha512-GCi7soURYBOu7TOEeqAcShKzaOxuN0w60+2BejCKWYe2VtzRvM8ACGTNXRcle/r/9JICiyw3LpxvieJpqdSnOw==} cpu: [arm64] os: [freebsd] + requiresBuild: true dev: true optional: true @@ -7882,6 +7967,7 @@ packages: resolution: {integrity: sha512-9+Yyig9JWkDgLT7Y4L9LPH4ik0Tlb3E2ac2fJFI4shMp2ETcV1ehyjDXT/LzLTSkf4mGLsww+WYKtzXJNVThRg==} cpu: [ia32] os: [linux] + requiresBuild: true dev: true optional: true @@ -7889,6 +7975,7 @@ packages: resolution: {integrity: sha512-MDnDrfWrtK4BOWh2+a3nrkFacjtEy7sUZnnIhTqUM5FOKD8ISh8VTS3C16hi2BfAjCnZhqIrynbNH/P1YH6j3Q==} cpu: [x64] os: [linux] + requiresBuild: true dev: true optional: true @@ -7896,6 +7983,7 @@ packages: resolution: {integrity: sha512-Vx2YIFhNqgz4L3Z7zKauPmhgA4QzEtUsjekN0HeEpkZkhWONbcF2gc2j9LTNzicLbI+RoiKrwJWt9qkydqU6mg==} cpu: [arm] os: [linux] + requiresBuild: true dev: true optional: true @@ -7903,6 +7991,7 @@ packages: resolution: {integrity: sha512-gs3mhARtzNBoEQn6S05mefYrmcKtWJexwnDQiQZ8fXIkAE9IqvIWNk7S+MyixQH/11jwUqFPtRsn1yQWbvZDhQ==} cpu: [arm64] os: [linux] + requiresBuild: true dev: true optional: true @@ -7910,6 +7999,7 @@ packages: resolution: {integrity: sha512-99k9FbOJBbIjhoUOE4uOioh65kZI0VHZzf3JlhpYo3j9r+KGhu7aYTbbvd7j1qQ9o5vToic5vc3OkOm2LKgvig==} cpu: [mips64el] os: [linux] + requiresBuild: true dev: true optional: true @@ -7917,6 +8007,7 @@ packages: resolution: {integrity: sha512-M+/sBWQ4UXVplSt5/pIvIRBT6NfEOVFvcOpbzWNjAhLE0vE/ZYeU07S/HjRZd6PMiodT61UyC7BwDQOa2pDOQg==} cpu: [ppc64] os: [linux] + requiresBuild: true dev: true optional: true @@ -7924,6 +8015,7 @@ packages: resolution: {integrity: sha512-Y2R5ZmOHOTgr/pAQAVY39BpRDMRCjyaeLxwIAIkvyNSBpkU/TtnJZXMlt2so42Qv9Jren1mlvxm+g1nb0zAQQg==} cpu: [ia32] os: [win32] + requiresBuild: true dev: true optional: true @@ -7931,6 +8023,7 @@ packages: resolution: {integrity: sha512-F8tapVNGeWXdNSFJDybOSNWxmi6xF59oZIP7+c043D/IBvkIGTQG449QD9EdUtSq8pe20zM95VKmW9mUjqHYPQ==} cpu: [x64] os: [win32] + requiresBuild: true dev: true optional: true From b5f5b45814e3541d3290b6955af5d24651672b7a Mon Sep 17 00:00:00 2001 From: Fabien MARIE-LOUISE Date: Wed, 1 Jun 2022 08:47:30 +0200 Subject: [PATCH 02/52] feat(collection, selection, listbox): clean --- packages/collection/src/createCollection.ts | 129 --- packages/collection/src/index.ts | 3 +- packages/collection/src/types.ts | 110 --- packages/collection/src/utils.ts | 38 - .../collection/test/createCollection.test.ts | 392 -------- packages/collection/test/utils.test.ts | 95 -- packages/listbox/src/createListBox.ts | 230 ----- packages/listbox/src/createListBoxOption.ts | 225 ----- packages/listbox/src/createListBoxSection.ts | 104 --- packages/listbox/src/createListBoxState.ts | 138 --- packages/listbox/src/index.ts | 5 +- packages/listbox/test/createListBox.test.tsx | 4 +- .../selection/src/createListFocusManager.ts | 240 ----- .../selection/src/createSelectionManager.ts | 141 --- packages/selection/src/createTypeSelect.ts | 107 --- packages/selection/src/index.ts | 6 +- packages/selection/src/types.ts | 142 --- packages/selection/src/utils.ts | 30 - .../test/createListFocusManager.test.ts | 465 --------- .../test/createSelectionManager.test.ts | 879 ------------------ 20 files changed, 6 insertions(+), 3477 deletions(-) delete mode 100644 packages/collection/src/createCollection.ts delete mode 100644 packages/collection/src/types.ts delete mode 100644 packages/collection/src/utils.ts delete mode 100644 packages/collection/test/createCollection.test.ts delete mode 100644 packages/collection/test/utils.test.ts delete mode 100644 packages/listbox/src/createListBox.ts delete mode 100644 packages/listbox/src/createListBoxOption.ts delete mode 100644 packages/listbox/src/createListBoxSection.ts delete mode 100644 packages/listbox/src/createListBoxState.ts delete mode 100644 packages/selection/src/createListFocusManager.ts delete mode 100644 packages/selection/src/createSelectionManager.ts delete mode 100644 packages/selection/src/createTypeSelect.ts delete mode 100644 packages/selection/src/types.ts delete mode 100644 packages/selection/src/utils.ts delete mode 100644 packages/selection/test/createListFocusManager.test.ts delete mode 100644 packages/selection/test/createSelectionManager.test.ts diff --git a/packages/collection/src/createCollection.ts b/packages/collection/src/createCollection.ts deleted file mode 100644 index 138fcd8..0000000 --- a/packages/collection/src/createCollection.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { createMemo, createSignal } from "solid-js"; - -import { Collection, Item } from "./types"; -import { filterItems } from "./utils"; - -/** - * Create a reactive collection of items. - */ -export function createCollection(): Collection { - const [items, setItems] = createSignal>([]); - const keys = createMemo(() => items().map(item => item.key)); - - const isCollectionEmpty = () => { - return !items() || items().length <= 0; - }; - - const addItem = (item: Item) => { - setItems(prev => [...prev, item]); - }; - - const removeItem = (key: string) => { - setItems(prev => prev.filter(item => item.key !== key)); - }; - - const findByIndex = (index: number) => { - return items()[index] ?? null; - }; - - const findByKey = (key: string) => { - return items().find(item => item.key === key) ?? null; - }; - - const findIndexByKey = (key?: string) => { - return items().findIndex(item => item.key === key); - }; - - const findIndexBySearch = (filter: string, collator: Intl.Collator, startIndex: number) => { - // Access the reactive items once during the function execution. - const resolvedItems = items(); - - // Order the items to prioritize items after the given start index. - const orderedItems = [ - ...resolvedItems.slice(startIndex), - ...resolvedItems.slice(0, startIndex) - ]; - - // first check if there is an exact match for the typed string. - const firstMatch = filterItems(orderedItems, filter, collator)[0]; - - if (firstMatch) { - return resolvedItems.indexOf(firstMatch); - } - - // If the same letter is being repeated, cycle through first-letter matches. - const allSameLetter = (array: string[]) => array.every(letter => letter === array[0]); - - if (allSameLetter(filter.split(""))) { - const matches = filterItems(orderedItems, filter[0], collator); - return resolvedItems.indexOf(matches[0]); - } - - // No matches - return -1; - }; - - const getFirstIndex = () => { - if (isCollectionEmpty()) { - return -1; - } - - return 0; - }; - - const getLastIndex = () => { - if (isCollectionEmpty()) { - return -1; - } - - return items().length - 1; - }; - - const isFirstIndex = (index: number) => { - if (isCollectionEmpty()) { - return false; - } - - return index === getFirstIndex(); - }; - - const isLastIndex = (index: number) => { - if (isCollectionEmpty()) { - return false; - } - - return index === getLastIndex(); - }; - - return { - items, - keys, - addItem, - removeItem, - findByIndex, - findByKey, - findIndexByKey, - findIndexBySearch, - getFirstIndex, - getLastIndex, - isFirstIndex, - isLastIndex - }; -} diff --git a/packages/collection/src/index.ts b/packages/collection/src/index.ts index 2247c87..98368fa 100644 --- a/packages/collection/src/index.ts +++ b/packages/collection/src/index.ts @@ -15,5 +15,4 @@ * governing permissions and limitations under the License. */ -export * from "./createCollection"; -export * from "./types"; +export {}; diff --git a/packages/collection/src/types.ts b/packages/collection/src/types.ts deleted file mode 100644 index 25ce184..0000000 --- a/packages/collection/src/types.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { Accessor } from "solid-js"; - -export interface Item { - /** - * A unique key for the item. - */ - key: string; - - /** - * A string representation of the item's contents, used for features like typeahead. - */ - textValue: string; - - /** - * A ref to the root HTML element of the item. - */ - ref: HTMLElement; - - /** - * Whether the item is disabled. - */ - isDisabled: Accessor; -} - -/** - * An interface for dealing with collection. - */ -export interface Collection { - /** - * Get all items in the collection. - */ - items: Accessor>; - - /** - * Get all keys in the collection. - */ - keys: Accessor>; - - /** - * Add an item to the collection. - */ - addItem: (item: Item) => void; - - /** - * Remove a item from the collection. - */ - removeItem: (key: string) => void; - - /** - * Find a item by its index. - */ - findByIndex: (index: number) => Item | null; - - /** - * Find a item by its key. - */ - findByKey: (key: string) => Item | null; - - /** - * Find an index by the item key. - */ - findIndexByKey: (key?: string) => number; - - /** - * Find an index based on a filter string, returns -1 if not found. - * If the filter is multiple iterations of the same letter (e.g "aaa"), then cycle through first-letter matches. - * - * @param filter - The filter string to search. - * @param collator - The collator to use for string comparison. - * @param startIndex - The index in the collection to start search from. - */ - findIndexBySearch: (filter: string, collator: Intl.Collator, startIndex: number) => number; - - /** - * Get the first index in the collection, or -1 if empty. - */ - getFirstIndex: () => number; - - /** - * Get the last index in the collection, or -1 if empty. - */ - getLastIndex: () => number; - - /** - * Return whether the given index is the first one. - */ - isFirstIndex: (index: number) => boolean; - - /** - * Return whether the given index is the last one. - */ - isLastIndex: (index: number) => boolean; -} diff --git a/packages/collection/src/utils.ts b/packages/collection/src/utils.ts deleted file mode 100644 index 08e6023..0000000 --- a/packages/collection/src/utils.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { Item } from "./types"; - -/** - * Returns an array of non disabled items that begin with the filter string, case-independent. - * - * @param items - The collection of items to search into. - * @param filter - The filter string to search. - * @param collator - The collator to use for string comparison. - */ -export function filterItems(items: Item[], filter: string, collator: Intl.Collator) { - return items.filter(item => { - if (item.isDisabled()) { - return false; - } - - // Compare with a part of textValue with same length as the filter. - const substring = item.textValue.slice(0, filter.length); - - return collator.compare(substring, filter) === 0; - }); -} diff --git a/packages/collection/test/createCollection.test.ts b/packages/collection/test/createCollection.test.ts deleted file mode 100644 index 6645f1f..0000000 --- a/packages/collection/test/createCollection.test.ts +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { createRoot } from "solid-js"; - -import { createCollection } from "../src"; - -describe("createCollection", () => { - it("should add item to the collection", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.items().length).toBe(0); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.items().length).toBe(1); - - dispose(); - }); - }); - - it("should remove item to the collection", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.items().length).toBe(0); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.items().length).toBe(1); - - collection.removeItem(item1.key); - - expect(collection.items().length).toBe(0); - - dispose(); - }); - }); - - it("should returns all item's keys in the collection", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.keys().length).toBe(1); - expect(collection.keys()[0]).toBe("1"); - - dispose(); - }); - }); - - it("should retrieve an item by its index", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findByIndex(0)).toBe(item1); - - dispose(); - }); - }); - - it("should returns null when no item was found for a given index", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findByIndex(42)).toBe(null); - - dispose(); - }); - }); - - it("should retrieve an item by its key", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findByKey("1")).toBe(item1); - - dispose(); - }); - }); - - it("should returns null when no item was found for a given key", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findByKey("not exist")).toBe(null); - - dispose(); - }); - }); - - it("should retrieve an item index by its key", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findIndexByKey("1")).toBe(0); - - dispose(); - }); - }); - - it("should returns -1 when no item index was found for a given key", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findIndexByKey("not exists")).toBe(-1); - - dispose(); - }); - }); - - it("should retrieve an item index by searching in its textValue", () => { - createRoot(dispose => { - const collator = new Intl.Collator("en", { usage: "search", sensitivity: "base" }); - - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findIndexBySearch("O", collator, 0)).toBe(0); - - dispose(); - }); - }); - - it("should returns -1 when no item was found for a given textValue search", () => { - createRoot(dispose => { - const collator = new Intl.Collator("en", { usage: "search", sensitivity: "base" }); - - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - collection.addItem(item1); - - expect(collection.findIndexBySearch("T", collator, 0)).toBe(-1); - - dispose(); - }); - }); - - it("should retrieve first index", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => false - }; - - collection.addItem(item1); - collection.addItem(item2); - - expect(collection.getFirstIndex()).toBe(0); - - dispose(); - }); - }); - - it("should returns -1 for first index when collection is empty", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.getFirstIndex()).toBe(-1); - - dispose(); - }); - }); - - it("should retrieve last index", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => false - }; - - collection.addItem(item1); - collection.addItem(item2); - - expect(collection.getLastIndex()).toBe(1); - - dispose(); - }); - }); - - it("should returns -1 for last index when collection is empty", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.getLastIndex()).toBe(-1); - - dispose(); - }); - }); - - it("should returns whether given index is the first one", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => false - }; - - collection.addItem(item1); - collection.addItem(item2); - - expect(collection.isFirstIndex(0)).toBeTruthy(); - - dispose(); - }); - }); - - it("should returns false when checking first index match and collection is empty", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.isFirstIndex(0)).toBe(false); - - dispose(); - }); - }); - - it("should returns whether given index is the last one", () => { - createRoot(dispose => { - const collection = createCollection(); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => false - }; - - collection.addItem(item1); - collection.addItem(item2); - - expect(collection.isLastIndex(1)).toBeTruthy(); - - dispose(); - }); - }); - - it("should returns false when checking last index match and collection is empty", () => { - createRoot(dispose => { - const collection = createCollection(); - - expect(collection.isLastIndex(0)).toBe(false); - - dispose(); - }); - }); -}); diff --git a/packages/collection/test/utils.test.ts b/packages/collection/test/utils.test.ts deleted file mode 100644 index 788a31e..0000000 --- a/packages/collection/test/utils.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { createRoot } from "solid-js"; - -import { filterItems } from "../src/utils"; - -describe("filterItems", () => { - it("should returns items matching the given filter", () => { - createRoot(dispose => { - const collator = new Intl.Collator("en", { usage: "search", sensitivity: "base" }); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => false - }; - - const item3 = { - key: "3", - ref: document.createElement("div"), - textValue: "Three", - isDisabled: () => false - }; - - const items = [item1, item2, item3]; - - const filteredItems = filterItems(items, "T", collator); - - expect(filteredItems.length).toBe(2); - expect(filteredItems[0]).toBe(item2); - expect(filteredItems[1]).toBe(item3); - - dispose(); - }); - }); - - it("should ignore disabled items", () => { - createRoot(dispose => { - const collator = new Intl.Collator("en", { usage: "search", sensitivity: "base" }); - - const item1 = { - key: "1", - ref: document.createElement("div"), - textValue: "One", - isDisabled: () => false - }; - - const item2 = { - key: "2", - ref: document.createElement("div"), - textValue: "Two", - isDisabled: () => true - }; - - const item3 = { - key: "3", - ref: document.createElement("div"), - textValue: "Three", - isDisabled: () => false - }; - - const items = [item1, item2, item3]; - - const filteredItems = filterItems(items, "T", collator); - - expect(filteredItems.length).toBe(1); - expect(filteredItems[0]).toBe(item3); - - dispose(); - }); - }); -}); diff --git a/packages/listbox/src/createListBox.ts b/packages/listbox/src/createListBox.ts deleted file mode 100644 index 94bdfae..0000000 --- a/packages/listbox/src/createListBox.ts +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2022 Solid Aria Working Group. - * MIT License - * - * Portions of this file are based on code from react-spectrum. - * Copyright 2020 Adobe. All rights reserved. - * - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import { createFocusable } from "@solid-aria/focus"; -import { AriaLabelProps, createLabel } from "@solid-aria/label"; -import { createTypeSelect, isCtrlKeyPressed, SelectionMode } from "@solid-aria/selection"; -import { AriaLabelingProps, DOMElements, DOMProps, LabelableProps } from "@solid-aria/types"; -import { filterDOMProps } from "@solid-aria/utils"; -import { combineProps } from "@solid-primitives/props"; -import { - Accessor, - createComponent, - createContext, - createMemo, - FlowComponent, - JSX, - mergeProps, - useContext -} from "solid-js"; - -import { createListBoxState, ListBoxState } from "./createListBoxState"; - -const ListBoxContext = createContext(); - -export interface AriaListBoxProps extends LabelableProps, DOMProps, AriaLabelingProps { - /** - * The currently selected keys in the listbox (controlled). - */ - selectedKeys?: Set; - - /** - * The initial selected keys in the listbox (uncontrolled). - */ - defaultSelectedKeys?: Set; - - /** - * The type of selection that is allowed in the listbox. - */ - selectionMode?: SelectionMode; - - /** - * Whether the listbox allows empty selection. - */ - allowEmptySelection?: boolean; - - /** - * Whether focus should wrap around when the end/start is reached. - */ - shouldFocusWrap?: boolean; - - /** - * Whether options should be focused when the user hovers over them. - */ - shouldFocusOnHover?: boolean; - - /** - * Whether selection should occur automatically on focus. - */ - selectOnFocus?: boolean; - - /** - * Whether the listbox should be automatically focused upon render. - */ - autoFocus?: boolean; - - /** - * Whether the listbox is disabled. - */ - isDisabled?: boolean; - - /** - * The rendered contents of the listbox. - */ - children?: JSX.Element; - - /** - * Handler that is called when the selection changes. - */ - onSelectionChange?: (keys: Set) => void; -} - -export interface ListBoxAria< - ListBoxElementType extends DOMElements, - LabelElementType extends DOMElements -> { - /** - * Provide the listbox state to descendant elements. - */ - ListBoxProvider: FlowComponent; - - /** - * State for the listbox, as returned by `createListBoxState`. - */ - state: ListBoxState; - - /** - * Props for the listbox element. - */ - listBoxProps: Accessor; - - /** - * Props for the listbox's visual label element (if any). - */ - labelProps: Accessor; -} - -/** - * Provides the behavior and accessibility implementation for a listbox component. - * A listbox displays a list of options and allows a user to select one or more of them. - * @param props - Props for the listbox. - * @param ref - A ref for the HTML listbox element. - * @param scrollRef - The ref attached to the scrollable body, if not provided the listbox ref will be used. - */ -export function createListBox< - ListBoxElementType extends DOMElements = "ul", - LabelElementType extends DOMElements = "div", - RefElement extends HTMLElement = HTMLUListElement ->( - props: AriaListBoxProps, - ref: Accessor, - scrollRef?: Accessor -): ListBoxAria { - const defaultCreateLabelProps: AriaLabelProps = { - // listbox is not an HTML input element so it - // shouldn't be labeled by a