From 1b702663adb0d04e318921c53ca9b95217639c14 Mon Sep 17 00:00:00 2001 From: Tim Ellenberger Date: Fri, 6 Nov 2026 19:02:31 -0700 Subject: [PATCH 01/15] chore: replace ESLint and Prettier with oxlint and oxfmt oxfmt and oxlint replace Prettier and ESLint 8. The oxlint config keeps this repo's sort rules, with the destructuring sort rule as a small local JS plugin, and adds correctness and style rules. This commit swaps the tools and runs `oxfmt --write` over master's code. The next commit fixes what oxlint reports. Co-Authored-By: Claude Opus 5.5 --- .changeset/brave-queens-press.md | 4 + .eslintignore | 34 - .eslintrc.js | 79 - .github/workflows/test.yml | 4 +- .oxfmtrc.json | 36 + .oxlintrc.json | 223 + .prettierignore | 15 - .prettierrc.js | 11 - .vscode/extensions.json | 3 + .vscode/settings.json | 10 +- CHANGELOG.md | 116 +- README.md | 24 +- e2e/accessibility.spec.ts | 32 +- e2e/coverage.ts | 8 +- e2e/harness/index.html | 10 +- e2e/harness/main.tsx | 44 +- e2e/ignored-input.spec.ts | 42 +- e2e/images-and-layout.spec.ts | 56 +- e2e/inline.spec.ts | 34 +- e2e/opening-and-closing.spec.ts | 54 +- e2e/paging.spec.ts | 73 +- e2e/panning.spec.ts | 39 +- e2e/support.ts | 53 +- e2e/tsconfig.json | 1 - e2e/zoom-transforms.spec.ts | 58 +- e2e/zooming.spec.ts | 88 +- .../GalleryLightbox/components/GridImage.jsx | 6 +- .../components/LightboxArrowButton.jsx | 28 +- .../components/LightboxButtonControl.jsx | 2 +- .../components/LightboxHeader.jsx | 13 +- example/components/GalleryLightbox/index.jsx | 24 +- example/components/InlineLightbox/index.jsx | 5 +- example/pages/_app.jsx | 1 + example/pages/index.tsx | 23 +- package-lock.json | 7565 ++++++----------- package.json | 39 +- playwright.config.ts | 4 +- rollup.config.mjs | 4 +- scripts/add-release-dates.mjs | 7 +- scripts/add-release-dates.test.mjs | 6 +- .../oxlint-plugin-sort-destructure-keys.mjs | 182 + src/__tests__/customization.test.tsx | 30 +- src/__tests__/devices.ts | 77 +- src/__tests__/embedding.test.tsx | 149 +- src/__tests__/helpers.tsx | 58 +- src/__tests__/inline.test.tsx | 27 +- src/__tests__/opening-and-closing.test.tsx | 85 +- src/__tests__/paging.test.tsx | 134 +- src/__tests__/panning.test.tsx | 20 +- src/__tests__/public-types.test.ts | 6 +- src/__tests__/published-bundle.test.tsx | 24 +- src/__tests__/useDoubleClick.test.tsx | 24 +- src/__tests__/useRefSize.test.tsx | 20 +- src/__tests__/utils.test.ts | 72 +- src/__tests__/zoom-transforms.test.tsx | 81 +- src/__tests__/zooming.test.tsx | 51 +- .../ImageStage/components/Image/index.tsx | 59 +- .../components/ImagePager/index.tsx | 39 +- .../SSRImagePager/SSRImagePager.tsx | 3 +- src/components/ImageStage/index.tsx | 14 +- .../utils/getTranslateOffsetsFromScale.ts | 3 +- .../ImageStage/utils/imageIsOutOfBounds.ts | 4 +- src/components/ImageStage/utils/index.ts | 7 +- src/components/PageContainer/index.tsx | 16 +- src/components/index.tsx | 2 +- src/index.tsx | 13 +- tsconfig.buildtypes.json | 1 - tsconfig.json | 1 - 68 files changed, 3703 insertions(+), 6377 deletions(-) create mode 100644 .changeset/brave-queens-press.md delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 .oxfmtrc.json create mode 100644 .oxlintrc.json delete mode 100644 .prettierignore delete mode 100644 .prettierrc.js create mode 100644 .vscode/extensions.json create mode 100644 scripts/oxlint-plugin-sort-destructure-keys.mjs diff --git a/.changeset/brave-queens-press.md b/.changeset/brave-queens-press.md new file mode 100644 index 0000000..68e2660 --- /dev/null +++ b/.changeset/brave-queens-press.md @@ -0,0 +1,4 @@ +--- +--- + +Replace ESLint and Prettier with oxlint and oxfmt. Nothing changes for people who install the package. diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 10f24a4..0000000 --- a/.eslintignore +++ /dev/null @@ -1,34 +0,0 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. - -# dependencies -/node_modules -example/node_modules/** - -# production -/build -/dist -/coverage -/playwright-report -/test-results -/blob-report -/e2e/harness/images -/e2e/harness/index.html - -# misc -.DS_Store -.env -npm-debug.log* -yarn-debug.log* -yarn-error.log* -package-lock.json* -package.json* -CHANGELOG.md* -README.md* - -example/.DS_Store -example/.env -example/npm-debug.log* -example/yarn-debug.log* -example/yarn-error.log* -example/next-env.d.ts -*.css diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index eb98bd8..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable sort-keys */ -/** - * Configure ESLint - * - * https://eslint.org/docs/user-guide/configuring - */ -module.exports = { - env: { - browser: true, - es6: true, - }, - extends: [ - 'plugin:react/recommended', - 'plugin:import/warnings', - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - ], - globals: { - document: true, - window: true, - }, - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module', - }, - plugins: [ - 'prettier', - 'jsx-a11y', - 'react', - 'react-hooks', - 'import', - 'sort-destructure-keys', - '@typescript-eslint', - ], - root: true, - rules: { - 'prettier/prettier': ['error', { endOfLine: 'auto' }], - // Enforce React Hooks rules - // https://www.npmjs.com/package/eslint-plugin-react-hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - - 'sort-destructure-keys/sort-destructure-keys': [ - 'error', - { caseSensitive: false }, - ], - 'sort-keys': ['error', 'asc', { caseSensitive: false, natural: false }], - 'sort-vars': [ - 'error', - { - ignoreCase: true, - }, - ], - 'react/jsx-sort-props': ['error', { ignoreCase: true }], - '@typescript-eslint/ban-ts-comment': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/member-ordering': [ - 'error', - { - default: { - order: 'alphabetically', - }, - classes: { - order: 'as-written', - }, - }, - ], - }, - settings: { - 'import/resolver': { - node: true, - 'eslint-import-resolver-typescript': true, - }, - react: { - version: 'detect', - }, - }, -}; diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7fe45af..817fff0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,8 +40,8 @@ jobs: node-version: 24 cache: npm - run: npm ci - - run: npm run lint:eslint - - run: npm run lint:prettier + - run: npm run lint:oxlint + - run: npm run lint:oxfmt # Vitest doesn't type-check, so tsc checks the tests along with the source - run: npm run lint:ts diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..3726676 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,36 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "singleQuote": true, + "tabWidth": 4, + "semi": true, + "trailingComma": "es5", + "printWidth": 120, + "arrowParens": "always", + "singleAttributePerLine": true, + "sortPackageJson": false, + "sortImports": { + "partitionByNewline": false, + "newlinesBetween": true, + "internalPattern": ["@/", "~/"], + "groups": [ + "type-import", + ["value-builtin", "value-external"], + "type-internal", + "value-internal", + ["type-parent", "type-sibling", "type-index"], + ["value-parent", "value-sibling", "value-index"], + "unknown" + ] + }, + "ignorePatterns": ["**/dist/**", "**/node_modules/**"], + "overrides": [ + { + "files": ["example/**"], + "options": { + "sortTailwindcss": { + "stylesheet": "./example/styles/globals.css" + } + } + } + ] +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..6dae038 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,223 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["eslint", "oxc", "unicorn", "typescript", "import", "react", "vitest", "jsx-a11y"], + "jsPlugins": ["./scripts/oxlint-plugin-sort-destructure-keys.mjs"], + "env": { + "builtin": true, + "browser": true, + "node": true + }, + "ignorePatterns": ["**/dist/**", "**/node_modules/**"], + "settings": { + "next": { + "rootDir": ["example"] + } + }, + "rules": { + "@typescript-eslint/consistent-generic-constructors": "error", + "array-callback-return": "error", + "curly": ["error", "all"], + "default-case": "error", + "eqeqeq": ["error", "always"], + "import/namespace": "off", + "import/no-absolute-path": "error", + "import/no-amd": "error", + "import/no-self-import": "error", + "import/no-webpack-loader-syntax": "error", + "jsx-a11y/aria-activedescendant-has-tabindex": "error", + "jsx-a11y/aria-props": "error", + "jsx-a11y/aria-proptypes": "error", + "jsx-a11y/aria-role": "error", + "jsx-a11y/aria-unsupported-elements": "error", + "jsx-a11y/heading-has-content": "error", + "jsx-a11y/img-redundant-alt": "error", + "jsx-a11y/no-access-key": "error", + "jsx-a11y/no-distracting-elements": "error", + "jsx-a11y/no-redundant-roles": "error", + "jsx-a11y/role-has-required-aria-props": "error", + "jsx-a11y/scope": "error", + "no-array-constructor": "error", + "no-caller": "error", + "no-cond-assign": ["error", "except-parens"], + "no-console": "error", + "no-debugger": "error", + "no-duplicate-imports": [ + "error", + { + "allowSeparateTypeImports": true + } + ], + "no-else-return": "error", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "off", + "no-extra-label": "error", + "no-fallthrough": "error", + "no-implicit-coercion": "error", + "no-implied-eval": "error", + "no-invalid-regexp": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": [ + "error", + { + "allowLoop": true, + "allowSwitch": false + } + ], + "no-lone-blocks": "error", + "no-lonely-if": "error", + "no-loop-func": "error", + "no-multi-str": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-param-reassign": "error", + "no-proto": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-restricted-globals": [ + "error", + "addEventListener", + "blur", + "close", + "closed", + "confirm", + "defaultStatus", + "defaultstatus", + "event", + "external", + "find", + "focus", + "frameElement", + "frames", + "history", + "innerHeight", + "innerWidth", + "length", + "location", + "locationbar", + "menubar", + "moveBy", + "moveTo", + "name", + "onblur", + "onerror", + "onfocus", + "onload", + "onresize", + "onunload", + "open", + "opener", + "opera", + "outerHeight", + "outerWidth", + "pageXOffset", + "pageYOffset", + "parent", + "print", + "removeEventListener", + "resizeBy", + "resizeTo", + "screen", + "screenLeft", + "screenTop", + "screenX", + "screenY", + "scroll", + "scrollbars", + "scrollBy", + "scrollTo", + "scrollX", + "scrollY", + "self", + "status", + "statusbar", + "stop", + "toolbar", + "top" + ], + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow-restricted-names": "error", + "no-template-curly-in-string": "error", + "no-throw-literal": "error", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "no-useless-concat": "error", + "no-useless-constructor": "error", + "no-useless-escape": "error", + "no-useless-rename": [ + "error", + { + "ignoreDestructuring": false, + "ignoreExport": false, + "ignoreImport": false + } + ], + "no-with": "error", + "react-hooks/exhaustive-deps": "error", + "react-hooks/rules-of-hooks": "error", + "react/jsx-boolean-value": "error", + "react/jsx-curly-brace-presence": "error", + "react/jsx-no-comment-textnodes": "error", + "react/jsx-no-duplicate-props": "error", + "react/jsx-no-undef": "error", + "react/no-danger": "error", + "react/no-danger-with-children": "error", + "react/no-direct-mutation-state": "error", + "react/no-is-mounted": "error", + "react/no-unknown-property": "error", + "react/require-render-return": "error", + "require-yield": "error", + "sort-destructure-keys/sort-destructure-keys": "error", + "sort-keys": [ + "error", + "asc", + { + "caseSensitive": false, + "natural": false + } + ], + "sort-vars": [ + "error", + { + "ignoreCase": true + } + ], + "unicode-bom": ["error", "never"], + "vitest/expect-expect": [ + "error", + { + "assertFunctionNames": ["expect", "expect*", "keepsInPlace", "pinchWith"] + } + ], + "vitest/prefer-to-have-length": "error", + "vitest/require-mock-type-parameters": "off" + }, + "overrides": [ + { + "files": ["example/**"], + "plugins": ["nextjs"], + "rules": { + "nextjs/no-img-element": "off" + } + }, + { + "files": ["scripts/**"], + "rules": { + "no-console": "off" + } + } + ] +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 73d4f47..0000000 --- a/.prettierignore +++ /dev/null @@ -1,15 +0,0 @@ -node_modules/** -.next/** -dist/** -coverage/** -playwright-report/** -test-results/** -blob-report/** -e2e/harness/images/** -example/node_modules/** -example/.next/** -.editorconfig -.eslintignore -.gitignore -.prettierignore -.browserslistrc diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index a611401..0000000 --- a/.prettierrc.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Configure Prettier - * - * https://prettier.io/docs/en/configuration.html#basic-configuration - */ -module.exports = { - endOfLine: 'auto', - semi: true, - singleQuote: true, - tabWidth: 4, -}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..9d5eb3d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["oxc.oxc-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 032486e..359d2d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,13 @@ "javascript.validate.enable": false, "editor.tabSize": 4, "editor.detectIndentation": false, - "eslint.enable": true + "[javascript][javascriptreact][typescript][typescriptreact]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[json][jsonc][yaml][css][html][markdown]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "editor.codeActionsOnSave": { + "source.fixAll.oxc": "always" + } } diff --git a/CHANGELOG.md b/CHANGELOG.md index de00836..6e36a50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,16 @@ ## [1.9.0] - 2026-07-29 -- Drop `styled-components` dependency +- Drop `styled-components` dependency ## [1.8.0] - 2023-10-06 -- Add inline mode SSR support -- fix next.js + styled-components + SWC client/server classname mismatch error -- Upgrade several dependencies - - @react-spring/web ^9.7 - - rollup 3 - - typescript 5 +- Add inline mode SSR support +- fix next.js + styled-components + SWC client/server classname mismatch error +- Upgrade several dependencies + - @react-spring/web ^9.7 + - rollup 3 + - typescript 5 ### Potentially Breaking @@ -21,32 +21,32 @@ ### Fixed -- Allow vertical scrolling with an InlineLightbox on mobile (even while finger is over the image) +- Allow vertical scrolling with an InlineLightbox on mobile (even while finger is over the image) ## [1.7.0] - 2022-07-28 -- A few small bug fixes in situations where the `items` array may change size -- Upgrade several dependencies - - "@react-spring/web": "9.5.2" - - "rollup": "^2.77.2", +- A few small bug fixes in situations where the `items` array may change size +- Upgrade several dependencies + - "@react-spring/web": "9.5.2" + - "rollup": "^2.77.2", ### Added -- `Lightbox` can now be used as a slider component embedded in a page like slick-slider by using the `inline` prop +- `Lightbox` can now be used as a slider component embedded in a page like slick-slider by using the `inline` prop ## [1.6.0] - 2021-06-06 -- Upgrade to `@react-spring/web@9.2.1` stable from `@tim-soft/react-spring-web@9.0.0-beta.36` +- Upgrade to `@react-spring/web@9.2.1` stable from `@tim-soft/react-spring-web@9.0.0-beta.36` ## [1.5.0] - 2021-02-17 -- Rewrite project with typescript 4 -- Upgrade `react-use-gesture@7.0.15` to `react-use-gesture@9.0.4` - - This upgrade should fix some miscellaneous bugs such as `unable to spread non iterable instance` and more consistent trackpad support +- Rewrite project with typescript 4 +- Upgrade `react-use-gesture@7.0.15` to `react-use-gesture@9.0.4` + - This upgrade should fix some miscellaneous bugs such as `unable to spread non iterable instance` and more consistent trackpad support ### Added -- The `images` prop now accepts a list of objects whose properties can be _almost_ any valid React `` prop including `srcset` and `loading` (lazy loading) +- The `images` prop now accepts a list of objects whose properties can be _almost_ any valid React `` prop including `srcset` and `loading` (lazy loading) If you use typescript, the exact type can be imported/used like this @@ -90,146 +90,146 @@ Which translates to any React `` prop minus `draggable`, `onClick`, `onDr ### Fixed -- Use aliased version of react-spring dependencies, fixes "Cannot read property 'ref' of null" error +- Use aliased version of react-spring dependencies, fixes "Cannot read property 'ref' of null" error ## [1.4.10] - 2020-05-03 ### Added -- Optimize output bundles with Terser -- Apply `babel-plugin-styled-components` babel plugin to optimize styled-components styles +- Optimize output bundles with Terser +- Apply `babel-plugin-styled-components` babel plugin to optimize styled-components styles ## [1.4.9] - 2020-05-02 ### Fixed -- Fix partially off-screen image stage in ie11 +- Fix partially off-screen image stage in ie11 ### Added -- Upgrade to `rollup@2.7.6`, `react-use-gesture@7.0.15` and `@babel/****@7.9.6` +- Upgrade to `rollup@2.7.6`, `react-use-gesture@7.0.15` and `@babel/****@7.9.6` ## [1.4.8] - 2020-04-08 ### Fixed -- Dropped `lodash.clamp` dependency -- Call onPrev/onNext callbacks on all paging events, even at the beginning or end of image array to allow for infinite paging +- Dropped `lodash.clamp` dependency +- Call onPrev/onNext callbacks on all paging events, even at the beginning or end of image array to allow for infinite paging ## [1.4.7] - 2020-04-05 ### Added -- Lower distance and velocity gesture threshold for a paging between images -- Allow click to zoom while a paging animation completes -- Upgrade to `rollup@2.3.3` and `react-use-gesture@7.0.10` -- Add `sideEffects: false` to `package.json` +- Lower distance and velocity gesture threshold for a paging between images +- Allow click to zoom while a paging animation completes +- Upgrade to `rollup@2.3.3` and `react-use-gesture@7.0.10` +- Add `sideEffects: false` to `package.json` ## [1.4.6] - 2020-04-04 ### Fixed -- Handle edge case bugs with `singleClickToZoom` option -- Fix undefined errors in panning drag handler on initial drags +- Handle edge case bugs with `singleClickToZoom` option +- Fix undefined errors in panning drag handler on initial drags ## [1.4.5] - 2020-03-27 ### Added -- Add optional `singleClickToZoom` prop which allows single click/tap zooming on images +- Add optional `singleClickToZoom` prop which allows single click/tap zooming on images ## [1.4.4] - 2020-03-24 ### Fixed -- Add orientationchange event listener for ios devices +- Add orientationchange event listener for ios devices ## [1.4.3] - 2020-03-23 ### Fixed -- Drop lodash.merge -- Fix image heights not adjusting on window resize +- Drop lodash.merge +- Fix image heights not adjusting on window resize ## [1.4.2] - 2020-03-15 ### Fixed -- Remove need for react-use-measure and @juggle/resize-observer +- Remove need for react-use-measure and @juggle/resize-observer ## [1.4.1] - 2020-03-13 ### Fixed -- Fix image stage height on Safari -- Upgrade to react-use-gesture@7.0.5 -- Upgrade to rollup@2.0.6 +- Fix image stage height on Safari +- Upgrade to react-use-gesture@7.0.5 +- Upgrade to rollup@2.0.6 ## [1.4.0] - 2020-03-7 ### BREAKING CHANGE -- Replaced inline styles with styled-components. This library now has a peer dependency on `styled-components@5` +- Replaced inline styles with styled-components. This library now has a peer dependency on `styled-components@5` ### Fixed -- Gigantic initial image size in Firefox and MS Edge -- Click background to close functionality +- Gigantic initial image size in Firefox and MS Edge +- Click background to close functionality ### Added -- Vendor prefixed styles -- A resize observer polyfill is now included to support MS Edge +- Vendor prefixed styles +- A resize observer polyfill is now included to support MS Edge ## [1.2.1] - 2020-03-5 ### Added -- Added `renderImageOverlay` prop, renders a React component within the image stage, useful for creating UI overlays on top of the current image +- Added `renderImageOverlay` prop, renders a React component within the image stage, useful for creating UI overlays on top of the current image ## [1.2.0] - 2020-02-14 -- Upgrade react-use-gesture v6 -> v7 -- Upgrade all deps +- Upgrade react-use-gesture v6 -> v7 +- Upgrade all deps ## [1.1.7] - 2019-09-23 ### Fixed -- Improved panning performance -- Tweaked mousewheel swiping threshold -- Upgrade to react-use-gesture v6 +- Improved panning performance +- Tweaked mousewheel swiping threshold +- Upgrade to react-use-gesture v6 ## [1.1.4] - 2019-08-27 ### Added -- Implement mousewheel paging of images +- Implement mousewheel paging of images ## [1.1.3] - 2019-08-19 ### Fixed -- Prevent vertical dragging from paging images -- Switch to @react-spring/web package +- Prevent vertical dragging from paging images +- Switch to @react-spring/web package ## [1.1.2] - 2019-08-17 ### Fixed -- Properly dispose wheel event listener +- Properly dispose wheel event listener ## [1.1.1] - 2019-08-14 ### Fixed -- Adjusted "pan out of bounds" threshold +- Adjusted "pan out of bounds" threshold ## [1.1.0] - 2019-08-14 ### Added -- Implement proper Ctrl + `Mousewheel` and `Trackpad Pinch` zooming +- Implement proper Ctrl + `Mousewheel` and `Trackpad Pinch` zooming ## [1.0.1] - 2019-08-7 @@ -243,8 +243,8 @@ Upgrade deps and release as stable ### Changed -- Renamed onClickNext => onNext -- Renamed onClickPrev => onPrev +- Renamed onClickNext => onNext +- Renamed onClickPrev => onPrev ## [0.0.2] - 2019-07-31 diff --git a/README.md b/README.md index c4d4e4c..6c98c9d 100644 --- a/README.md +++ b/README.md @@ -21,18 +21,18 @@ React-spring-lightbox is a flexible image gallery lightbox with native-feeling t ## ✨ Features -- :point_up:    `Mousewheel`, swipe or click+drag to page photos -- :keyboard:  Keyboard controls ← → Esc -- :mouse2:  Ctrl + `Mousewheel` or `Trackpad Pinch` to zoom -- :mag_right:  Double/Single-tap or double/single-click to zoom in/out -- :ok_hand:    Pinch to zoom -- :point_left:  Panning on zoomed-in images -- :checkered_flag:  Highly performant spring based animations via [react-spring](https://github.com/react-spring/react-spring) -- No external CSS -- Implement your own UI -- Supports IE 11, Edge, Safari, Chrome, Firefox and Opera -- Full typescript support -- Supports any `` attribute including `loading` (lazy loading), `srcset` and `aria-*` +- :point_up:    `Mousewheel`, swipe or click+drag to page photos +- :keyboard:  Keyboard controls ← → Esc +- :mouse2:  Ctrl + `Mousewheel` or `Trackpad Pinch` to zoom +- :mag_right:  Double/Single-tap or double/single-click to zoom in/out +- :ok_hand:    Pinch to zoom +- :point_left:  Panning on zoomed-in images +- :checkered_flag:  Highly performant spring based animations via [react-spring](https://github.com/react-spring/react-spring) +- No external CSS +- Implement your own UI +- Supports IE 11, Edge, Safari, Chrome, Firefox and Opera +- Full typescript support +- Supports any `` attribute including `loading` (lazy loading), `srcset` and `aria-*` ## Install diff --git a/e2e/accessibility.spec.ts b/e2e/accessibility.spec.ts index 53c3aa4..41ef24f 100644 --- a/e2e/accessibility.spec.ts +++ b/e2e/accessibility.spec.ts @@ -1,4 +1,5 @@ import type { Page } from '@playwright/test'; + import { expect, openHarness, sampleFrames, settle, test } from './support'; // What keyboard, screen reader and reduced-motion users need from a modal. @@ -13,12 +14,7 @@ const openWithKeyboard = async (page: Page) => { }; const focusIsInLightbox = (page: Page) => - page.evaluate( - () => - !!document.activeElement?.closest( - '[data-testid="lightbox-container"]', - ), - ); + page.evaluate(() => !!document.activeElement?.closest('[data-testid="lightbox-container"]')); test.describe('with a keyboard', () => { test.skip(({ isMobile }) => isMobile, 'Keyboard input'); @@ -29,9 +25,7 @@ test.describe('with a keyboard', () => { await page.keyboard.press('Escape'); await expect(page.getByTestId('lightbox-container')).toHaveCount(0); - await expect( - page.getByRole('button', { name: 'Open Image 3' }), - ).toBeFocused(); + await expect(page.getByRole('button', { name: 'Open Image 3' })).toBeFocused(); }); test('focus moves into the lightbox when it opens', async ({ page }) => { @@ -42,14 +36,8 @@ test.describe('with a keyboard', () => { expect(focusInside).toBe(true); }); - test('Tab cycles through the lightbox, never reaching the page behind', async ({ - browserName, - page, - }) => { - test.skip( - browserName === 'webkit', - 'WebKit on macOS tabs only to text fields by default', - ); + test('Tab cycles through the lightbox, never reaching the page behind', async ({ browserName, page }) => { + test.skip(browserName === 'webkit', 'WebKit on macOS tabs only to text fields by default'); await openWithKeyboard(page); const stayedInside: boolean[] = []; for (let press = 0; press < 6; press += 1) { @@ -70,18 +58,12 @@ test.describe('with a keyboard', () => { }); }); -test('opens without animating when the user prefers reduced motion', async ({ - page, -}) => { +test('opens without animating when the user prefers reduced motion', async ({ page }) => { await page.emulateMedia({ reducedMotion: 'reduce' }); await openHarness(page, 'closed'); await page.getByRole('button', { name: 'Open Image 3' }).click(); - const [firstFrame] = await sampleFrames( - page.getByTestId('lightbox-container'), - 'opacity', - 1, - ); + const [firstFrame] = await sampleFrames(page.getByTestId('lightbox-container'), 'opacity', 1); test.fail(true, 'The springs ignore prefers-reduced-motion'); expect(firstFrame).toBe(1); diff --git a/e2e/coverage.ts b/e2e/coverage.ts index f84a335..fb3383e 100644 --- a/e2e/coverage.ts +++ b/e2e/coverage.ts @@ -1,7 +1,8 @@ -import path from 'node:path'; -import { CoverageReport } from 'monocart-coverage-reports'; import type { CoverageReportOptions } from 'monocart-coverage-reports'; +import { CoverageReport } from 'monocart-coverage-reports'; +import path from 'node:path'; + // With E2E_COVERAGE set, the e2e tests record which lines of the library's // source Chromium runs, and write coverage/e2e/lcov.info for Codecov @@ -9,8 +10,7 @@ export const measuringCoverage = Boolean(process.env.E2E_COVERAGE); export const coverageOptions: CoverageReportOptions = { // Vite serves the library's modules from their paths on disk, under /@fs/ - entryFilter: (entry) => - entry.url.includes('/src/') && !entry.url.includes('/node_modules/'), + entryFilter: (entry) => entry.url.includes('/src/') && !entry.url.includes('/node_modules/'), name: 'E2E coverage', outputDir: 'coverage/e2e', reports: ['lcovonly', 'console-summary'], diff --git a/e2e/harness/index.html b/e2e/harness/index.html index ee5bda5..9e863e6 100644 --- a/e2e/harness/index.html +++ b/e2e/harness/index.html @@ -2,7 +2,10 @@ - + react-spring-lightbox test harness