diff --git a/CHANGELOG.md b/CHANGELOG.md index 46ab695a9..2923f608d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +### Code Refactoring + +- fixing remaining TS errors ([918544c](https://github.com/adevinta/spark/commit/918544c278a370ec82384842cc8f60b59982eb9f)) + +### BREAKING CHANGES + +- forwardRef has been removed from all packages + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package spark diff --git a/lerna.json b/lerna.json index 6c8b35704..310d00d2e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "7.3.7", + "version": "8.0.0", "command": { "publish": { "conventionalCommits": true, diff --git a/package-lock.json b/package-lock.json index cc458a5c5..8f5f701e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29573,14 +29573,14 @@ }, "packages/components/accordion": { "name": "@spark-ui/accordion", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/collapsible": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/collapsible": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "@zag-js/accordion": "0.81.0", "@zag-js/react": "0.81.0" }, @@ -29594,12 +29594,12 @@ }, "packages/components/alert-dialog": { "name": "@spark-ui/alert-dialog", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.0.1", - "@spark-ui/dialog": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/dialog": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29618,10 +29618,10 @@ }, "packages/components/badge": { "name": "@spark-ui/badge", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29634,13 +29634,13 @@ }, "packages/components/breadcrumb": { "name": "@spark-ui/breadcrumb", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/text-link": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/text-link": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29653,12 +29653,12 @@ }, "packages/components/button": { "name": "@spark-ui/button", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/spinner": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/spinner": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29671,16 +29671,16 @@ }, "packages/components/checkbox": { "name": "@spark-ui/checkbox", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-checkbox": "1.0.4", - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/label": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/label": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29693,13 +29693,13 @@ }, "packages/components/chip": { "name": "@spark-ui/chip", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "emulate-tab": "^1.2.1" }, "peerDependencies": { @@ -29712,11 +29712,11 @@ }, "packages/components/collapsible": { "name": "@spark-ui/collapsible", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "@zag-js/collapsible": "0.81.0", "@zag-js/react": "0.81.0" }, @@ -29730,22 +29730,22 @@ }, "packages/components/combobox": { "name": "@spark-ui/combobox", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/popover": "^7.3.7", - "@spark-ui/spinner": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/popover": "^8.0.0", + "@spark-ui/spinner": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0", "class-variance-authority": "0.7.0", "downshift": "9.0.7" }, "devDependencies": { - "@spark-ui/dialog": "^7.3.7" + "@spark-ui/dialog": "^8.0.0" }, "peerDependencies": { "react": "^19.0", @@ -29755,13 +29755,13 @@ }, "packages/components/dialog": { "name": "@spark-ui/dialog", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-dialog": "1.1.2", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29774,11 +29774,11 @@ }, "packages/components/divider": { "name": "@spark-ui/divider", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-separator": "1.1.0", - "@spark-ui/internal-utils": "^7.3.7" + "@spark-ui/internal-utils": "^8.0.0" }, "peerDependencies": { "react": "^19.0", @@ -29788,13 +29788,13 @@ }, "packages/components/drawer": { "name": "@spark-ui/drawer", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-dialog": "1.1.2", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29807,15 +29807,15 @@ }, "packages/components/dropdown": { "name": "@spark-ui/dropdown", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/popover": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/popover": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0", "class-variance-authority": "0.7.0", "downshift": "9.0.7" }, @@ -29827,13 +29827,13 @@ }, "packages/components/form-field": { "name": "@spark-ui/form-field", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/label": "^7.3.7", - "@spark-ui/slot": "^7.3.7" + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/label": "^8.0.0", + "@spark-ui/slot": "^8.0.0" }, "peerDependencies": { "@spark-ui/tailwind-plugins": "latest", @@ -29845,11 +29845,11 @@ }, "packages/components/icon": { "name": "@spark-ui/icon", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7" + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0" }, "peerDependencies": { "@spark-ui/tailwind-plugins": "latest", @@ -29861,10 +29861,10 @@ }, "packages/components/icon-button": { "name": "@spark-ui/icon-button", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/button": "^7.3.7", + "@spark-ui/button": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29877,7 +29877,7 @@ }, "packages/components/icons": { "name": "@spark-ui/icons", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "devDependencies": { "change-case": "4.1.2", @@ -29916,15 +29916,15 @@ }, "packages/components/input": { "name": "@spark-ui/input", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/use-combined-state": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/use-combined-state": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29937,7 +29937,7 @@ }, "packages/components/kbd": { "name": "@spark-ui/kbd", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "class-variance-authority": "0.7.0" @@ -29952,7 +29952,7 @@ }, "packages/components/label": { "name": "@spark-ui/label", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-label": "2.1.0", @@ -29968,10 +29968,10 @@ }, "packages/components/link-box": { "name": "@spark-ui/link-box", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/slot": "^7.3.7", + "@spark-ui/slot": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -29982,14 +29982,14 @@ }, "packages/components/pagination": { "name": "@spark-ui/pagination", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/button": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", + "@spark-ui/button": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", "@zag-js/pagination": "0.81.0", "@zag-js/react": "0.81.0" }, @@ -30003,13 +30003,13 @@ }, "packages/components/popover": { "name": "@spark-ui/popover", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-popover": "1.1.1", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7" + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0" }, "devDependencies": { "jsdom-testing-mocks": "1.13.1" @@ -30024,7 +30024,7 @@ }, "packages/components/portal": { "name": "@spark-ui/portal", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-portal": "1.1.2", @@ -30098,11 +30098,11 @@ }, "packages/components/progress": { "name": "@spark-ui/progress", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-progress": "1.1.0", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30115,11 +30115,11 @@ }, "packages/components/progress-tracker": { "name": "@spark-ui/progress-tracker", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30132,13 +30132,13 @@ }, "packages/components/radio-group": { "name": "@spark-ui/radio-group", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-label": "2.1.0", "@radix-ui/react-radio-group": "1.2.1", - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30151,11 +30151,11 @@ }, "packages/components/rating": { "name": "@spark-ui/rating", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "devDependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7" + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0" }, "peerDependencies": { "react": "^19.0", @@ -30165,13 +30165,13 @@ }, "packages/components/select": { "name": "@spark-ui/select", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/use-combined-state": "^7.3.7" + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/use-combined-state": "^8.0.0" }, "peerDependencies": { "react": "^19.0", @@ -30181,11 +30181,11 @@ }, "packages/components/skeleton": { "name": "@spark-ui/skeleton", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30198,7 +30198,7 @@ }, "packages/components/slider": { "name": "@spark-ui/slider", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-slider": "1.2.1", @@ -30217,7 +30217,7 @@ }, "packages/components/slot": { "name": "@spark-ui/slot", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.1.1" @@ -30230,14 +30230,14 @@ }, "packages/components/snackbar": { "name": "@spark-ui/snackbar", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@react-aria/toast": "^3.0.0-beta.18", "@react-stately/toast": "3.0.0-beta.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30250,11 +30250,11 @@ }, "packages/components/spinner": { "name": "@spark-ui/spinner", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30267,17 +30267,17 @@ }, "packages/components/stepper": { "name": "@spark-ui/stepper", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@react-aria/button": "3.11.0", "@react-aria/numberfield": "3.11.9", "@react-stately/numberfield": "3.9.6", - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/input": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7" + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/input": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0" }, "peerDependencies": { "@react-types/numberfield": "3.8.5", @@ -30290,16 +30290,16 @@ }, "packages/components/switch": { "name": "@spark-ui/switch", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-switch": "1.1.0", - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/label": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/use-combined-state": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/label": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/use-combined-state": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30354,13 +30354,13 @@ }, "packages/components/tabs": { "name": "@spark-ui/tabs", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@radix-ui/react-tabs": "1.1.1", - "@spark-ui/button": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/button": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" }, "devDependencies": { @@ -30376,11 +30376,11 @@ }, "packages/components/tag": { "name": "@spark-ui/tag", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30391,10 +30391,10 @@ }, "packages/components/text-link": { "name": "@spark-ui/text-link", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/slot": "^7.3.7", + "@spark-ui/slot": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { @@ -30405,10 +30405,10 @@ }, "packages/components/textarea": { "name": "@spark-ui/textarea", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/input": "^7.3.7" + "@spark-ui/input": "^8.0.0" }, "peerDependencies": { "@spark-ui/tailwind-plugins": "latest", @@ -30420,7 +30420,7 @@ }, "packages/components/visually-hidden": { "name": "@spark-ui/visually-hidden", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "peerDependencies": { "react": "^19.0", @@ -30430,10 +30430,10 @@ }, "packages/hooks/use-combined-state": { "name": "@spark-ui/use-combined-state", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/use-mounted-state": "^7.3.7", + "@spark-ui/use-mounted-state": "^8.0.0", "@types/lodash.isequal": "4.5.8", "lodash.isequal": "4.5.0" }, @@ -30444,7 +30444,7 @@ }, "packages/hooks/use-merge-refs": { "name": "@spark-ui/use-merge-refs", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "peerDependencies": { "react": "^19.0", @@ -30453,7 +30453,7 @@ }, "packages/hooks/use-mounted-state": { "name": "@spark-ui/use-mounted-state", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "peerDependencies": { "react": "^19.0", @@ -30462,7 +30462,7 @@ }, "packages/utils/cli": { "name": "@spark-ui/cli-utils", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "@clack/prompts": "0.7.0", @@ -30574,7 +30574,7 @@ }, "packages/utils/internal-utils": { "name": "@spark-ui/internal-utils", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "peerDependencies": { "react": "^19.0", @@ -30583,10 +30583,10 @@ }, "packages/utils/tailwind-plugins": { "name": "@spark-ui/tailwind-plugins", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { - "@spark-ui/theme-utils": "^7.3.7", + "@spark-ui/theme-utils": "^8.0.0", "tailwindcss-radix": "2.9.0" }, "peerDependencies": { @@ -30595,7 +30595,7 @@ }, "packages/utils/theme": { "name": "@spark-ui/theme-utils", - "version": "7.3.7", + "version": "8.0.0", "license": "MIT", "dependencies": { "deepmerge": "4.3.1", diff --git a/packages/components/accordion/CHANGELOG.md b/packages/components/accordion/CHANGELOG.md index c5cb82862..5d43b4ec5 100644 --- a/packages/components/accordion/CHANGELOG.md +++ b/packages/components/accordion/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/accordion + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/accordion diff --git a/packages/components/accordion/package.json b/packages/components/accordion/package.json index 4e5dad3e3..dcad4af90 100644 --- a/packages/components/accordion/package.json +++ b/packages/components/accordion/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/accordion", - "version": "7.3.7", + "version": "8.0.0", "description": "An accordion is a vertically stacked set of interactive headings containing a title, content snippet, or thumbnail representing a section of content.", "publishConfig": { "access": "public" @@ -45,11 +45,11 @@ "homepage": "https://sparkui.vercel.app", "license": "MIT", "dependencies": { - "@spark-ui/collapsible": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/collapsible": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "@zag-js/accordion": "0.81.0", "@zag-js/react": "0.81.0" } diff --git a/packages/components/accordion/src/Accordion.tsx b/packages/components/accordion/src/Accordion.tsx index 56eb005bc..a20211eec 100644 --- a/packages/components/accordion/src/Accordion.tsx +++ b/packages/components/accordion/src/Accordion.tsx @@ -3,7 +3,7 @@ import { Slot } from '@spark-ui/slot' import * as accordion from '@zag-js/accordion' import { mergeProps, normalizeProps, type PropTypes, useMachine } from '@zag-js/react' import { cx } from 'class-variance-authority' -import { type ComponentPropsWithoutRef, createContext, forwardRef, useContext, useId } from 'react' +import { type ComponentPropsWithoutRef, createContext, Ref, useContext, useId } from 'react' type ExtentedZagInterface = Omit< accordion.Context, @@ -38,6 +38,7 @@ export interface AccordionProps extends ExtentedZagInterface { */ onValueChange?: (value: string[]) => void design?: 'filled' | 'outlined' + ref?: Ref } const AccordionContext = createContext< @@ -47,68 +48,64 @@ const AccordionContext = createContext< | null >(null) -export const Accordion = forwardRef( - ( - { - asChild = false, - children, - collapsible = true, - className, - defaultValue, - design = 'outlined', - disabled = false, - multiple = false, - value, - onValueChange, - ...props - }, - ref - ) => { - const [machineProps, localProps] = accordion.splitProps({ - children, - multiple, - collapsible, - value, - disabled, - // onValueChange, - className: cx('bg-surface rounded-lg h-fit', className), - ...props, - }) +export const Accordion = ({ + asChild = false, + children, + collapsible = true, + className, + defaultValue, + design = 'outlined', + disabled = false, + multiple = false, + value, + onValueChange, + ref, + ...props +}: AccordionProps) => { + const [machineProps, localProps] = accordion.splitProps({ + children, + multiple, + collapsible, + value, + disabled, + // onValueChange, + className: cx('bg-surface rounded-lg h-fit', className), + ...props, + }) - const [state, send] = useMachine( - // Initial state - accordion.machine({ + const [state, send] = useMachine( + // Initial state + accordion.machine({ + ...machineProps, + value: defaultValue, + id: useId(), + onValueChange(details) { + onValueChange?.(details.value) + }, + }), + // Dynamic state + { + context: { ...machineProps, - value: defaultValue, - id: useId(), - onValueChange(details) { + onValueChange: useEvent((details: accordion.ValueChangeDetails) => { onValueChange?.(details.value) - }, - }), - // Dynamic state - { - context: { - ...machineProps, - onValueChange: useEvent((details: accordion.ValueChangeDetails) => { - onValueChange?.(details.value) - }), - }, - } - ) + }), + }, + } + ) - const Component = asChild ? Slot : 'div' - const api = accordion.connect(state, send, normalizeProps) - const mergedProps = mergeProps(api.getRootProps(), localProps) + const Component = asChild ? Slot : 'div' + const api = accordion.connect(state, send, normalizeProps) + const mergedProps = mergeProps(api.getRootProps(), localProps) - return ( - - - {children} - - - ) - } -) + return ( + + + {children} + + + ) +} Accordion.displayName = 'Accordion' diff --git a/packages/components/accordion/src/AccordionItem.tsx b/packages/components/accordion/src/AccordionItem.tsx index de3859c31..735a6c24e 100644 --- a/packages/components/accordion/src/AccordionItem.tsx +++ b/packages/components/accordion/src/AccordionItem.tsx @@ -1,7 +1,7 @@ import { Collapsible } from '@spark-ui/collapsible' import { mergeProps } from '@zag-js/react' import { cx } from 'class-variance-authority' -import { type ComponentPropsWithoutRef, forwardRef } from 'react' +import { type ComponentPropsWithoutRef, Ref } from 'react' import { useAccordionContext } from './Accordion' import { AccordionItemProvider } from './AccordionItemContext' @@ -10,43 +10,50 @@ export interface AccordionItemProps extends ComponentPropsWithoutRef<'div'> { value: string asChild?: boolean disabled?: boolean + ref?: Ref } -export const Item = forwardRef( - ({ asChild = false, className, children, disabled = false, value, ...props }, ref) => { - const accordion = useAccordionContext() - - const localProps = { - className: cx( - 'relative first:rounded-t-lg last:rounded-b-lg', - '[&:not(:last-child)]:border-b-none', - { 'border-sm border-outline': accordion.design === 'outlined' }, - className - ), - asChild, - ...props, - } - - const itemProps = accordion.getItemProps({ value, ...(disabled && { disabled }) }) - const mergedProps = mergeProps(itemProps, localProps) - - const item = accordion.getItemState({ value }) - const itemContentProps = accordion.getItemContentProps({ value }) - - return ( - - - {children} - - - ) +export const Item = ({ + asChild = false, + className, + children, + disabled = false, + value, + ref, + ...props +}: AccordionItemProps) => { + const accordion = useAccordionContext() + + const localProps = { + className: cx( + 'relative first:rounded-t-lg last:rounded-b-lg', + '[&:not(:last-child)]:border-b-none', + { 'border-sm border-outline': accordion.design === 'outlined' }, + className + ), + asChild, + ...props, } -) + + const itemProps = accordion.getItemProps({ value, ...(disabled && { disabled }) }) + const mergedProps = mergeProps(itemProps, localProps) + + const item = accordion.getItemState({ value }) + const itemContentProps = accordion.getItemContentProps({ value }) + + return ( + + + {children} + + + ) +} Item.displayName = 'Accordion.Item' diff --git a/packages/components/accordion/src/AccordionItemContent.tsx b/packages/components/accordion/src/AccordionItemContent.tsx index 9904e713f..78fa3401b 100644 --- a/packages/components/accordion/src/AccordionItemContent.tsx +++ b/packages/components/accordion/src/AccordionItemContent.tsx @@ -2,13 +2,14 @@ import { Collapsible } from '@spark-ui/collapsible' import { createSplitProps } from '@spark-ui/internal-utils' import { mergeProps } from '@zag-js/react' import { cx } from 'class-variance-authority' -import { type ComponentPropsWithoutRef, forwardRef } from 'react' +import { type ComponentPropsWithoutRef, Ref } from 'react' import { useAccordionContext } from './Accordion' import { useAccordionItemContext } from './AccordionItemContext' export interface AccordionItemContentProps extends ComponentPropsWithoutRef<'div'> { asChild?: boolean + ref?: Ref } const splitVisibilityProps = createSplitProps<{ @@ -16,31 +17,35 @@ const splitVisibilityProps = createSplitProps<{ 'data-state'?: string }>() -export const ItemContent = forwardRef( - ({ asChild = false, className, children, ...props }, ref) => { - const accordion = useAccordionContext() - const accordionItem = useAccordionItemContext() - - const localProps = { - className: cx('[&>:first-child]:p-lg', 'text-body-1 text-on-surface', className), - asChild, - ...props, - } - const contentProps = accordion.getItemContentProps({ - value: accordionItem.value, - ...(accordionItem.disabled && { disabled: accordionItem.disabled }), - }) - - const [, itemContentProps] = splitVisibilityProps(contentProps, ['hidden', 'data-state']) - - const mergedProps = mergeProps(itemContentProps, localProps) - - return ( - - {children} - - ) +export const ItemContent = ({ + asChild = false, + className, + children, + ref, + ...props +}: AccordionItemContentProps) => { + const accordion = useAccordionContext() + const accordionItem = useAccordionItemContext() + + const localProps = { + className: cx('[&>:first-child]:p-lg', 'text-body-1 text-on-surface', className), + asChild, + ...props, } -) + const contentProps = accordion.getItemContentProps({ + value: accordionItem.value, + ...(accordionItem.disabled && { disabled: accordionItem.disabled }), + }) + + const [, itemContentProps] = splitVisibilityProps(contentProps, ['hidden', 'data-state']) + + const mergedProps = mergeProps(itemContentProps, localProps) + + return ( + + {children} + + ) +} ItemContent.displayName = 'Accordion.ItemContent' diff --git a/packages/components/accordion/src/AccordionItemHeader.tsx b/packages/components/accordion/src/AccordionItemHeader.tsx index e7a6cd18b..5905bd729 100644 --- a/packages/components/accordion/src/AccordionItemHeader.tsx +++ b/packages/components/accordion/src/AccordionItemHeader.tsx @@ -1,25 +1,29 @@ import { Slot } from '@spark-ui/slot' import { cx } from 'class-variance-authority' -import { type ComponentProps, forwardRef } from 'react' +import { type ComponentProps, Ref } from 'react' export interface AccordionItemHeaderProps extends ComponentProps<'h3'> { asChild?: boolean + ref?: Ref } -export const ItemHeader = forwardRef( - ({ asChild = false, children, className }, ref) => { - const Component = asChild ? Slot : 'h3' +export const ItemHeader = ({ + asChild = false, + children, + className, + ref, +}: AccordionItemHeaderProps) => { + const Component = asChild ? Slot : 'h3' - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} ItemHeader.displayName = 'Accordion.ItemHeader' diff --git a/packages/components/accordion/src/AccordionItemTrigger.tsx b/packages/components/accordion/src/AccordionItemTrigger.tsx index 0e8d544fc..03c7f3272 100644 --- a/packages/components/accordion/src/AccordionItemTrigger.tsx +++ b/packages/components/accordion/src/AccordionItemTrigger.tsx @@ -3,56 +3,61 @@ import { ArrowHorizontalDown } from '@spark-ui/icons/dist/icons/ArrowHorizontalD import { Slot } from '@spark-ui/slot' import { mergeProps } from '@zag-js/react' import { cx } from 'class-variance-authority' -import { type ComponentPropsWithoutRef, forwardRef } from 'react' +import { type ComponentPropsWithoutRef, Ref } from 'react' import { useAccordionContext } from './Accordion' import { useAccordionItemContext } from './AccordionItemContext' export interface AccordionItemTriggerProps extends ComponentPropsWithoutRef<'button'> { asChild?: boolean + ref?: Ref } -export const ItemTrigger = forwardRef( - ({ asChild = false, children, className, ...props }, ref) => { - const { getItemTriggerProps } = useAccordionContext() - const { value, disabled } = useAccordionItemContext() - - const Component = asChild ? Slot : 'button' - - const localProps = { - ...props, - className: cx( - 'relative flex gap-lg justify-between items-center min-h-sz-48', - 'w-full px-lg py-md text-left text-headline-2 text-on-surface rounded-[inherit] data-[state=open]:rounded-b-none', - 'hover:enabled:bg-surface-hovered focus:bg-surface-hovered', - 'focus-visible:u-ring focus-visible:outline-none focus-visible:z-raised', - 'disabled:opacity-dim-3 disabled:cursor-not-allowed', - className - ), - } - - const mergedProps = mergeProps( - getItemTriggerProps({ value, ...(disabled && { disabled }) }), - localProps - ) - - const isOpen = !!mergedProps['aria-expanded'] - - return ( - -
{children}
- - - -
- ) +export const ItemTrigger = ({ + asChild = false, + children, + className, + ref, + ...props +}: AccordionItemTriggerProps) => { + const { getItemTriggerProps } = useAccordionContext() + const { value, disabled } = useAccordionItemContext() + + const Component = asChild ? Slot : 'button' + + const localProps = { + ...props, + className: cx( + 'relative flex gap-lg justify-between items-center min-h-sz-48', + 'w-full px-lg py-md text-left text-headline-2 text-on-surface rounded-[inherit] data-[state=open]:rounded-b-none', + 'hover:enabled:bg-surface-hovered focus:bg-surface-hovered', + 'focus-visible:u-ring focus-visible:outline-none focus-visible:z-raised', + 'disabled:opacity-dim-3 disabled:cursor-not-allowed', + className + ), } -) + + const mergedProps = mergeProps( + getItemTriggerProps({ value, ...(disabled && { disabled }) }), + localProps + ) + + const isOpen = !!mergedProps['aria-expanded'] + + return ( + +
{children}
+ + + +
+ ) +} ItemTrigger.displayName = 'Accordion.ItemTrigger' diff --git a/packages/components/alert-dialog/CHANGELOG.md b/packages/components/alert-dialog/CHANGELOG.md index 51715caaa..bcc6e8510 100644 --- a/packages/components/alert-dialog/CHANGELOG.md +++ b/packages/components/alert-dialog/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/alert-dialog + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/alert-dialog diff --git a/packages/components/alert-dialog/package.json b/packages/components/alert-dialog/package.json index c9dd36bc5..a5e06a27a 100644 --- a/packages/components/alert-dialog/package.json +++ b/packages/components/alert-dialog/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/alert-dialog", - "version": "7.3.7", + "version": "8.0.0", "description": "A modal dialog that interrupts the user with important content and expects a response.", "publishConfig": { "access": "public" @@ -24,8 +24,8 @@ }, "dependencies": { "@radix-ui/primitive": "1.0.1", - "@spark-ui/dialog": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/dialog": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { diff --git a/packages/components/alert-dialog/src/AlertDialogAction.tsx b/packages/components/alert-dialog/src/AlertDialogAction.tsx index f294a1639..5d64301d1 100644 --- a/packages/components/alert-dialog/src/AlertDialogAction.tsx +++ b/packages/components/alert-dialog/src/AlertDialogAction.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogCloseProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogActionElement = ElementRef -export type AlertDialogActionProps = DialogCloseProps +export type AlertDialogActionProps = DialogCloseProps & { + ref?: Ref +} -export const AlertDialogAction = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogAction = (props: AlertDialogActionProps) => { + return +} AlertDialogAction.displayName = 'AlertDialog.Action' diff --git a/packages/components/alert-dialog/src/AlertDialogBody.tsx b/packages/components/alert-dialog/src/AlertDialogBody.tsx index 6f02b001a..08a964729 100644 --- a/packages/components/alert-dialog/src/AlertDialogBody.tsx +++ b/packages/components/alert-dialog/src/AlertDialogBody.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogBodyProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogBodyElement = ElementRef -export type AlertDialogBodyProps = DialogBodyProps +export type AlertDialogBodyProps = DialogBodyProps & { + ref?: Ref +} -export const AlertDialogBody = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogBody = (props: AlertDialogBodyProps) => { + return +} AlertDialogBody.displayName = 'AlertDialog.Body' diff --git a/packages/components/alert-dialog/src/AlertDialogCancel.tsx b/packages/components/alert-dialog/src/AlertDialogCancel.tsx index 8967c2a14..066f1bde0 100644 --- a/packages/components/alert-dialog/src/AlertDialogCancel.tsx +++ b/packages/components/alert-dialog/src/AlertDialogCancel.tsx @@ -1,19 +1,18 @@ import { Dialog, DialogCloseProps } from '@spark-ui/dialog' import { useMergeRefs } from '@spark-ui/use-merge-refs' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' import { useAlertDialog } from './AlertDialogContext' -export type AlertDialogCancelElement = ElementRef -export type AlertDialogCancelProps = DialogCloseProps +export type AlertDialogCancelProps = DialogCloseProps & { + ref?: Ref +} -export const AlertDialogCancel = forwardRef( - (props, forwardedRef) => { - const { cancelRef } = useAlertDialog() - const ref = useMergeRefs(forwardedRef, cancelRef) +export const AlertDialogCancel = ({ ref: forwardedRef, ...props }: AlertDialogCancelProps) => { + const { cancelRef } = useAlertDialog() + const ref = useMergeRefs(forwardedRef, cancelRef) - return - } -) + return +} AlertDialogCancel.displayName = 'AlertDialog.Cancel' diff --git a/packages/components/alert-dialog/src/AlertDialogContent.tsx b/packages/components/alert-dialog/src/AlertDialogContent.tsx index 144a90210..aab0197a8 100644 --- a/packages/components/alert-dialog/src/AlertDialogContent.tsx +++ b/packages/components/alert-dialog/src/AlertDialogContent.tsx @@ -1,54 +1,58 @@ import { composeEventHandlers } from '@radix-ui/primitive' import { Dialog, DialogContentProps } from '@spark-ui/dialog' import { cx } from 'class-variance-authority' -import { ElementRef, forwardRef, useMemo, useRef } from 'react' +import { Ref, useMemo, useRef } from 'react' import { AlertDialogContext } from './AlertDialogContext' -export type AlertDialogContentElement = ElementRef export type AlertDialogContentProps = Omit< DialogContentProps, 'size' | 'isNarrow' | 'onPointerDownOutside' | 'onInteractOutside' -> - -export const AlertDialogContent = forwardRef( - ({ className, onOpenAutoFocus, ...others }, ref) => { - const cancelRef = useRef(null) - - const value = useMemo(() => { - return { cancelRef } - }, []) - - const handleOpenAutoFocus = (event: Event) => { - event.preventDefault() - cancelRef.current?.focus({ preventScroll: true }) - } - - const handlePointerDownOutside = (event: Event) => { - event.preventDefault() - } - - const handleInteractOutside = (event: Event) => { - event.preventDefault() - } - - return ( - - - - ) +> & { + ref?: Ref +} + +export const AlertDialogContent = ({ + className, + onOpenAutoFocus, + ref, + ...others +}: AlertDialogContentProps) => { + const cancelRef = useRef(null) + + const value = useMemo(() => { + return { cancelRef } + }, []) + + const handleOpenAutoFocus = (event: Event) => { + event.preventDefault() + cancelRef.current?.focus({ preventScroll: true }) } -) + + const handlePointerDownOutside = (event: Event) => { + event.preventDefault() + } + + const handleInteractOutside = (event: Event) => { + event.preventDefault() + } + + return ( + + + + ) +} AlertDialogContent.displayName = 'AlertDialog.Content' diff --git a/packages/components/alert-dialog/src/AlertDialogDescription.tsx b/packages/components/alert-dialog/src/AlertDialogDescription.tsx index a06e19c0c..3a686d573 100644 --- a/packages/components/alert-dialog/src/AlertDialogDescription.tsx +++ b/packages/components/alert-dialog/src/AlertDialogDescription.tsx @@ -1,14 +1,12 @@ import { Dialog, DialogDescriptionProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogDescriptionElement = ElementRef -export type AlertDialogDescriptionProps = DialogDescriptionProps +export type AlertDialogDescriptionProps = DialogDescriptionProps & { + ref?: Ref +} -export const AlertDialogDescription = forwardRef< - AlertDialogDescriptionElement, - AlertDialogDescriptionProps ->((props, ref) => { - return -}) +export const AlertDialogDescription = (props: AlertDialogDescriptionProps) => { + return +} AlertDialogDescription.displayName = 'AlertDialog.Description' diff --git a/packages/components/alert-dialog/src/AlertDialogFooter.tsx b/packages/components/alert-dialog/src/AlertDialogFooter.tsx index 59761fd42..a54d46875 100644 --- a/packages/components/alert-dialog/src/AlertDialogFooter.tsx +++ b/packages/components/alert-dialog/src/AlertDialogFooter.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogFooterProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogFooterElement = ElementRef -export type AlertDialogFooterProps = DialogFooterProps +export type AlertDialogFooterProps = DialogFooterProps & { + ref?: Ref +} -export const AlertDialogFooter = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogFooter = (props: AlertDialogFooterProps) => { + return +} AlertDialogFooter.displayName = 'AlertDialog.Footer' diff --git a/packages/components/alert-dialog/src/AlertDialogHeader.tsx b/packages/components/alert-dialog/src/AlertDialogHeader.tsx index 26ca6480d..ac2dbee3b 100644 --- a/packages/components/alert-dialog/src/AlertDialogHeader.tsx +++ b/packages/components/alert-dialog/src/AlertDialogHeader.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogHeaderProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogHeaderElement = ElementRef -export type AlertDialogHeaderProps = DialogHeaderProps +export type AlertDialogHeaderProps = DialogHeaderProps & { + ref?: Ref +} -export const AlertDialogHeader = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogHeader = (props: AlertDialogHeaderProps) => { + return +} AlertDialogHeader.displayName = 'AlertDialog.Header' diff --git a/packages/components/alert-dialog/src/AlertDialogOverlay.tsx b/packages/components/alert-dialog/src/AlertDialogOverlay.tsx index 4de7d87ad..0b016f89e 100644 --- a/packages/components/alert-dialog/src/AlertDialogOverlay.tsx +++ b/packages/components/alert-dialog/src/AlertDialogOverlay.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogOverlayProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogOverlayElement = ElementRef -export type AlertDialogOverlayProps = DialogOverlayProps +export type AlertDialogOverlayProps = DialogOverlayProps & { + ref?: Ref +} -export const AlertDialogOverlay = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogOverlay = (props: AlertDialogOverlayProps) => { + return +} AlertDialogOverlay.displayName = 'AlertDialog.Overlay' diff --git a/packages/components/alert-dialog/src/AlertDialogTitle.tsx b/packages/components/alert-dialog/src/AlertDialogTitle.tsx index cabcd1f85..8fb803c22 100644 --- a/packages/components/alert-dialog/src/AlertDialogTitle.tsx +++ b/packages/components/alert-dialog/src/AlertDialogTitle.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogTitleProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogTitleElement = ElementRef -export type AlertDialogTitleProps = DialogTitleProps +export type AlertDialogTitleProps = DialogTitleProps & { + ref?: Ref +} -export const AlertDialogTitle = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogTitle = (props: AlertDialogTitleProps) => { + return +} AlertDialogTitle.displayName = 'AlertDialog.Title' diff --git a/packages/components/alert-dialog/src/AlertDialogTrigger.tsx b/packages/components/alert-dialog/src/AlertDialogTrigger.tsx index 4a8434812..2bd4edb40 100644 --- a/packages/components/alert-dialog/src/AlertDialogTrigger.tsx +++ b/packages/components/alert-dialog/src/AlertDialogTrigger.tsx @@ -1,13 +1,12 @@ import { Dialog, DialogTriggerProps } from '@spark-ui/dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type AlertDialogTriggetElement = ElementRef -export type AlertDialogTriggerProps = DialogTriggerProps +export type AlertDialogTriggerProps = DialogTriggerProps & { + ref?: Ref +} -export const AlertDialogTrigger = forwardRef( - (props, ref) => { - return - } -) +export const AlertDialogTrigger = (props: AlertDialogTriggerProps) => { + return +} AlertDialogTrigger.displayName = 'AlertDialog.Trigger' diff --git a/packages/components/badge/CHANGELOG.md b/packages/components/badge/CHANGELOG.md index c7cb940fa..2c6be2040 100644 --- a/packages/components/badge/CHANGELOG.md +++ b/packages/components/badge/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/badge + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/badge diff --git a/packages/components/badge/package.json b/packages/components/badge/package.json index 58ddeea63..3c3332b9c 100644 --- a/packages/components/badge/package.json +++ b/packages/components/badge/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/badge", - "version": "7.3.7", + "version": "8.0.0", "description": "Badge component is a visual indicator for numeric values such as tallies and scores.", "publishConfig": { "access": "public" @@ -35,7 +35,7 @@ "url": "https://github.com/adevinta/spark/issues?q=is%3Aopen+is%3Aissue+label%3A%22Component%3A+badge%22" }, "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { diff --git a/packages/components/badge/src/Badge.tsx b/packages/components/badge/src/Badge.tsx index 2b7ce1972..5746777fb 100644 --- a/packages/components/badge/src/Badge.tsx +++ b/packages/components/badge/src/Badge.tsx @@ -1,20 +1,22 @@ -import { forwardRef, PropsWithChildren } from 'react' +import { PropsWithChildren, Ref } from 'react' import { BadgeItem, BadgeItemProps } from './BadgeItem' -export type BadgeProps = PropsWithChildren> +export type BadgeProps = PropsWithChildren> & { + ref?: Ref +} -export const Badge = forwardRef(({ children, ...props }, ref) => { +export const Badge = ({ children, ...props }: BadgeProps) => { const isStandalone = !children return isStandalone ? ( - + ) : (
{children} - +
) -}) +} Badge.displayName = 'Badge' diff --git a/packages/components/badge/src/BadgeItem.tsx b/packages/components/badge/src/BadgeItem.tsx index 8e1e34df2..ae3fc26c9 100644 --- a/packages/components/badge/src/BadgeItem.tsx +++ b/packages/components/badge/src/BadgeItem.tsx @@ -1,9 +1,9 @@ -import { forwardRef, HTMLAttributes, PropsWithRef } from 'react' +import { HTMLAttributes, Ref } from 'react' import { styles, type StylesProps } from './BadgeItem.styles' export interface BadgeItemProps - extends PropsWithRef, 'aria-label'>>, + extends Omit, 'aria-label'>, StylesProps { /** * Numeric value used as indicator inside the component. @@ -26,43 +26,38 @@ export interface BadgeItemProps * @default 'relative' */ type?: 'relative' | 'standalone' + ref?: Ref } -export const BadgeItem = forwardRef( - ( - { - intent = 'danger', - size = 'md', - type = 'relative', - count, - overflowCount = 99, - 'aria-label': label, - className, - ...others - }, - ref - ) => { - const hasOverflow = count && count > overflowCount - const ariaLabel = typeof label === 'function' ? label({ count, overflowCount }) : label - const props = { ...others, 'aria-label': ariaLabel } +export const BadgeItem = ({ + intent = 'danger', + size = 'md', + type = 'relative', + count, + overflowCount = 99, + 'aria-label': label, + className, + ...others +}: BadgeItemProps) => { + const hasOverflow = count && count > overflowCount + const ariaLabel = typeof label === 'function' ? label({ count, overflowCount }) : label + const props = { ...others, 'aria-label': ariaLabel } - return ( - - {hasOverflow ? `${overflowCount}+` : count} - - ) - } -) + return ( + + {hasOverflow ? `${overflowCount}+` : count} + + ) +} BadgeItem.displayName = 'BadgeItem' diff --git a/packages/components/breadcrumb/CHANGELOG.md b/packages/components/breadcrumb/CHANGELOG.md index f309c918d..5377dae1b 100644 --- a/packages/components/breadcrumb/CHANGELOG.md +++ b/packages/components/breadcrumb/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/breadcrumb + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/breadcrumb diff --git a/packages/components/breadcrumb/package.json b/packages/components/breadcrumb/package.json index 8bbce5fad..c4ce61c4e 100644 --- a/packages/components/breadcrumb/package.json +++ b/packages/components/breadcrumb/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/breadcrumb", - "version": "7.3.7", + "version": "8.0.0", "description": "navigation pattern that helps users understand the hierarchy of a website", "publishConfig": { "access": "public" @@ -30,10 +30,10 @@ "tailwindcss": "^3.0.0" }, "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/text-link": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/text-link": "^8.0.0", "class-variance-authority": "0.7.0" }, "repository": { diff --git a/packages/components/breadcrumb/src/Breadcrumb.tsx b/packages/components/breadcrumb/src/Breadcrumb.tsx index 4e62a0410..7efde7f6d 100644 --- a/packages/components/breadcrumb/src/Breadcrumb.tsx +++ b/packages/components/breadcrumb/src/Breadcrumb.tsx @@ -1,24 +1,28 @@ import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef } from 'react' +import { ComponentPropsWithoutRef, Ref } from 'react' export interface BreadcrumbProps extends ComponentPropsWithoutRef<'nav'> { className?: string ['aria-label']: string + ref?: Ref } -export const Breadcrumb = forwardRef( - ({ className, 'aria-label': ariaLabel, ...rest }, ref) => { - return ( - - ) - } -) +export const Breadcrumb = ({ + className, + 'aria-label': ariaLabel, + ref, + ...rest +}: BreadcrumbProps) => { + return ( + + ) +} Breadcrumb.displayName = 'Breadcrumb.Breadcrumb' diff --git a/packages/components/breadcrumb/src/BreadcrumbCurrentPage.tsx b/packages/components/breadcrumb/src/BreadcrumbCurrentPage.tsx index 5361aa1aa..1878bc782 100644 --- a/packages/components/breadcrumb/src/BreadcrumbCurrentPage.tsx +++ b/packages/components/breadcrumb/src/BreadcrumbCurrentPage.tsx @@ -1,34 +1,37 @@ import { Slot } from '@spark-ui/slot' import { TextLink } from '@spark-ui/text-link' import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef } from 'react' +import { ComponentPropsWithoutRef, Ref } from 'react' export interface CurrentPageProps extends ComponentPropsWithoutRef { asChild?: boolean className?: string + ref?: Ref } -export const CurrentPage = forwardRef( - ({ asChild = false, className, children, ...rest }, ref) => { - const Component = asChild ? Slot : 'span' +export const CurrentPage = ({ + asChild = false, + className, + children, + ...rest +}: CurrentPageProps) => { + const Component = asChild ? Slot : 'span' - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} CurrentPage.displayName = 'Breadcrumb.CurrentPage' diff --git a/packages/components/breadcrumb/src/BreadcrumbItem.tsx b/packages/components/breadcrumb/src/BreadcrumbItem.tsx index af454769c..d7d708803 100644 --- a/packages/components/breadcrumb/src/BreadcrumbItem.tsx +++ b/packages/components/breadcrumb/src/BreadcrumbItem.tsx @@ -1,19 +1,19 @@ import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef } from 'react' +import { ComponentPropsWithoutRef, Ref } from 'react' export interface ItemProps extends ComponentPropsWithoutRef<'li'> { className?: string + ref?: Ref } -export const Item = forwardRef(({ className, ...rest }, ref) => { +export const Item = ({ className, ...rest }: ItemProps) => { return (
  • ) -}) +} Item.displayName = 'Breadcrumb.Item' diff --git a/packages/components/breadcrumb/src/BreadcrumbLink.tsx b/packages/components/breadcrumb/src/BreadcrumbLink.tsx index 8c10c107a..c792743c9 100644 --- a/packages/components/breadcrumb/src/BreadcrumbLink.tsx +++ b/packages/components/breadcrumb/src/BreadcrumbLink.tsx @@ -1,42 +1,39 @@ import { Slot } from '@spark-ui/slot' import { TextLink } from '@spark-ui/text-link' import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef } from 'react' +import { ComponentPropsWithoutRef, Ref } from 'react' export interface LinkProps extends ComponentPropsWithoutRef { asChild?: boolean className?: string href?: string + ref?: Ref } -export const Link = forwardRef( - ( - { - asChild = false, - className, - bold = true, - intent = 'current', - underline = true, - href, - ...rest - }, - ref - ) => { - const Component = asChild ? Slot : TextLink +export const Link = ({ + asChild = false, + className, + bold = true, + intent = 'current', + underline = true, + href, + ref, + ...rest +}: LinkProps) => { + const Component = asChild ? Slot : TextLink - return ( - - ) - } -) + return ( + + ) +} Link.displayName = 'Breadcrumb.Link' diff --git a/packages/components/breadcrumb/src/BreadcrumbSeparator.tsx b/packages/components/breadcrumb/src/BreadcrumbSeparator.tsx index e4d8559da..d40bacada 100644 --- a/packages/components/breadcrumb/src/BreadcrumbSeparator.tsx +++ b/packages/components/breadcrumb/src/BreadcrumbSeparator.tsx @@ -2,34 +2,39 @@ import { Icon } from '@spark-ui/icon' import { ArrowVerticalRight } from '@spark-ui/icons/dist/icons/ArrowVerticalRight' import { Slot } from '@spark-ui/slot' import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef } from 'react' +import { ComponentPropsWithoutRef, Ref } from 'react' export interface SeparatorProps extends ComponentPropsWithoutRef<'li'> { asChild?: boolean className?: string + ref?: Ref } -export const Separator = forwardRef( - ({ asChild = false, className, children, ...rest }, ref) => { - const Component = asChild ? Slot : 'li' +export const Separator = ({ + asChild = false, + className, + children, + ref, + ...rest +}: SeparatorProps) => { + const Component = asChild ? Slot : 'li' - return ( - - {children ?? ( - - - - )} - - ) - } -) + return ( + + {children ?? ( + + + + )} + + ) +} Separator.displayName = 'Breadcrumb.Separator' diff --git a/packages/components/button/CHANGELOG.md b/packages/components/button/CHANGELOG.md index 0e6abc330..c048b1158 100644 --- a/packages/components/button/CHANGELOG.md +++ b/packages/components/button/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/button + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/button diff --git a/packages/components/button/package.json b/packages/components/button/package.json index 4238b32a0..40c5701e9 100644 --- a/packages/components/button/package.json +++ b/packages/components/button/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/button", - "version": "7.3.7", + "version": "8.0.0", "description": "Button component is used to trigger an action or event, such as submitting a form, opening a Dialog, canceling an action, or performing a delete operation.", "publishConfig": { "access": "public" @@ -23,9 +23,9 @@ "build": "vite build" }, "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", - "@spark-ui/spinner": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", + "@spark-ui/spinner": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { diff --git a/packages/components/button/src/Button.tsx b/packages/components/button/src/Button.tsx index 6ccb441eb..6811a3c07 100644 --- a/packages/components/button/src/Button.tsx +++ b/packages/components/button/src/Button.tsx @@ -1,7 +1,7 @@ import { Slot, wrapPolymorphicSlot } from '@spark-ui/slot' import { Spinner, type SpinnerProps } from '@spark-ui/spinner' import { cx } from 'class-variance-authority' -import React, { ComponentPropsWithoutRef, type DOMAttributes, forwardRef, useMemo } from 'react' +import React, { ComponentPropsWithoutRef, type DOMAttributes, Ref, useMemo } from 'react' import { buttonStyles, type ButtonStylesProps } from './Button.styles' @@ -25,6 +25,7 @@ export interface ButtonProps * **Please note that using this can result in layout shifting when the Button goes from loading state to normal state.** */ loadingText?: string + ref?: Ref } type DOMAttributesEventHandler = keyof Omit< @@ -46,83 +47,79 @@ const blockedEventHandlers: DOMAttributesEventHandler[] = [ 'onSubmit', ] -export const Button = forwardRef( - ( - { - children, - design = 'filled', - disabled = false, - intent = 'main', - isLoading = false, - loadingLabel, - loadingText, - shape = 'rounded', - size = 'md', - asChild, - className, - ...others - }, - ref - ) => { - const Component = asChild ? Slot : 'button' +export const Button = ({ + children, + design = 'filled', + disabled = false, + intent = 'main', + isLoading = false, + loadingLabel, + loadingText, + shape = 'rounded', + size = 'md', + asChild, + className, + ref, + ...others +}: ButtonProps) => { + const Component = asChild ? Slot : 'button' - const shouldNotInteract = !!disabled || isLoading + const shouldNotInteract = !!disabled || isLoading - const disabledEventHandlers = useMemo(() => { - const result: Partial void>> = {} + const disabledEventHandlers = useMemo(() => { + const result: Partial void>> = {} - if (shouldNotInteract) { - blockedEventHandlers.forEach(eventHandler => (result[eventHandler] = undefined)) - } - - return result - }, [shouldNotInteract]) - - const spinnerProps = { - size: 'current' as SpinnerProps['size'], - className: loadingText ? 'inline-block' : 'absolute', - ...(loadingLabel && { 'aria-label': loadingLabel }), + if (shouldNotInteract) { + blockedEventHandlers.forEach(eventHandler => (result[eventHandler] = undefined)) } - return ( - - {wrapPolymorphicSlot(asChild, children, slotted => - isLoading ? ( - <> - - {loadingText && loadingText} + return result + }, [shouldNotInteract]) -
    - {slotted} -
    - - ) : ( - slotted - ) - )} -
    - ) + const spinnerProps = { + size: 'current' as SpinnerProps['size'], + className: loadingText ? 'inline-block' : 'absolute', + ...(loadingLabel && { 'aria-label': loadingLabel }), } -) + + return ( + + {wrapPolymorphicSlot(asChild, children, slotted => + isLoading ? ( + <> + + {loadingText && loadingText} + +
    + {slotted} +
    + + ) : ( + slotted + ) + )} +
    + ) +} Button.displayName = 'Button' diff --git a/packages/components/checkbox/CHANGELOG.md b/packages/components/checkbox/CHANGELOG.md index 0f21c44a9..987e67e27 100644 --- a/packages/components/checkbox/CHANGELOG.md +++ b/packages/components/checkbox/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +### Code Refactoring + +- fixing remaining TS errors ([918544c](https://github.com/adevinta/spark/commit/918544c278a370ec82384842cc8f60b59982eb9f)) + +### BREAKING CHANGES + +- forwardRef has been removed from all packages + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/checkbox diff --git a/packages/components/checkbox/package.json b/packages/components/checkbox/package.json index 55a22b023..7f402e6ad 100644 --- a/packages/components/checkbox/package.json +++ b/packages/components/checkbox/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/checkbox", - "version": "7.3.7", + "version": "8.0.0", "description": "A control that allows the user to toggle between checked and not checked.", "publishConfig": { "access": "public" @@ -24,12 +24,12 @@ }, "dependencies": { "@radix-ui/react-checkbox": "1.0.4", - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/label": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/label": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", "class-variance-authority": "0.7.0" }, "peerDependencies": { diff --git a/packages/components/checkbox/src/Checkbox.tsx b/packages/components/checkbox/src/Checkbox.tsx index c59f94d16..55ea204c6 100644 --- a/packages/components/checkbox/src/Checkbox.tsx +++ b/packages/components/checkbox/src/Checkbox.tsx @@ -2,142 +2,141 @@ import { useFormFieldControl } from '@spark-ui/form-field' import { useMergeRefs } from '@spark-ui/use-merge-refs' import { cx } from 'class-variance-authority' -import { forwardRef, useId, useMemo, useRef } from 'react' +import { Ref, useId, useMemo, useRef } from 'react' import { CheckboxGroupContextState, useCheckboxGroup } from './CheckboxGroupContext' import { CheckboxInput, CheckboxInputProps } from './CheckboxInput' import { CheckboxLabel } from './CheckboxLabel' -export type CheckboxProps = CheckboxInputProps & Pick +export type CheckboxProps = CheckboxInputProps & + Pick & { + ref?: Ref + } const ID_PREFIX = ':checkbox' -export const Checkbox = forwardRef( - ( - { - id: idProp, - className, - intent: intentProp, - checked: checkedProp, - value, - disabled, - reverse = false, - onCheckedChange, - children, - ...others - }, - forwardedRef - ) => { - const checkboxId = `${ID_PREFIX}-${useId()}` - const innerId = idProp || checkboxId - - const innerLabelId = `${ID_PREFIX}-${useId()}` - - const field = useFormFieldControl() - const group = useCheckboxGroup() - - const rootRef = useRef(null) - const ref = useMergeRefs(forwardedRef, rootRef) - - const getCheckboxAttributes = ({ - fieldState, - groupState, - checkboxIntent, - }: { - fieldState: ReturnType - groupState: ReturnType - checkboxIntent: CheckboxInputProps['intent'] - }) => { - const name = fieldState.name ?? groupState.name - const isRequired = fieldState.isRequired ?? groupState.isRequired - const state = fieldState.state ?? groupState.state - const isInvalid = fieldState.isInvalid ?? groupState.isInvalid - - const isFieldEnclosed = fieldState.id !== groupState.id - const id = isFieldEnclosed ? fieldState.id : undefined - const description = isFieldEnclosed ? fieldState.description : undefined - - const intent = state ?? checkboxIntent ?? groupState.intent - - return { name, isRequired, isInvalid, id, description, intent } - } +export const Checkbox = ({ + id: idProp, + className, + intent: intentProp, + checked: checkedProp, + value, + disabled, + reverse = false, + onCheckedChange, + children, + ref: forwardedRef, + ...others +}: CheckboxProps) => { + const checkboxId = `${ID_PREFIX}-${useId()}` + const innerId = idProp || checkboxId + + const innerLabelId = `${ID_PREFIX}-${useId()}` + + const field = useFormFieldControl() + const group = useCheckboxGroup() + + const rootRef = useRef(null) + const ref = useMergeRefs(forwardedRef, rootRef) + + const getCheckboxAttributes = ({ + fieldState, + groupState, + checkboxIntent, + }: { + fieldState: ReturnType + groupState: ReturnType + checkboxIntent: CheckboxInputProps['intent'] + }) => { + const name = fieldState.name ?? groupState.name + const isRequired = fieldState.isRequired ?? groupState.isRequired + const state = fieldState.state ?? groupState.state + const isInvalid = fieldState.isInvalid ?? groupState.isInvalid + + const isFieldEnclosed = fieldState.id !== groupState.id + const id = isFieldEnclosed ? fieldState.id : undefined + const description = isFieldEnclosed ? fieldState.description : undefined + + const intent = state ?? checkboxIntent ?? groupState.intent + + return { name, isRequired, isInvalid, id, description, intent } + } - const checked = value ? group.value?.includes(value) : checkedProp + const checked = value ? group.value?.includes(value) : checkedProp - const handleCheckedChange = (isChecked: boolean) => { - onCheckedChange?.(isChecked) + const handleCheckedChange = (isChecked: boolean) => { + onCheckedChange?.(isChecked) - const rootRefValue = rootRef.current?.value - if (rootRefValue && group.onCheckedChange) { - group.onCheckedChange(isChecked, rootRefValue) - } + const rootRefValue = rootRef.current?.value + if (rootRefValue && group.onCheckedChange) { + group.onCheckedChange(isChecked, rootRefValue) } + } - const { - id, - name, - isInvalid, - description, - intent, - isRequired: isRequiredAttr, - } = getCheckboxAttributes({ - fieldState: field, - groupState: group, - checkboxIntent: intentProp, - }) - - const isRequired = useMemo(() => { - if (!group) return isRequiredAttr - - return isRequiredAttr ? !group.value?.length : false - }, [group, isRequiredAttr]) - - const checkboxLabel = children && ( - - {children} - - ) - - const checkboxInput = ( - + const { + id, + name, + isInvalid, + description, + intent, + isRequired: isRequiredAttr, + } = getCheckboxAttributes({ + fieldState: field, + groupState: group, + checkboxIntent: intentProp, + }) + + const isRequired = useMemo(() => { + if (!group) return isRequiredAttr + + return isRequiredAttr ? !group.value?.length : false + }, [group, isRequiredAttr]) + + const checkboxLabel = children && ( + + {children} + + ) + + const checkboxInput = ( + + ) + + const content = + group.reverse || reverse ? ( + <> + {checkboxLabel} + {checkboxInput} + + ) : ( + <> + {checkboxInput} + {checkboxLabel} + ) - const content = - group.reverse || reverse ? ( - <> - {checkboxLabel} - {checkboxInput} - - ) : ( - <> - {checkboxInput} - {checkboxLabel} - - ) - - return ( -
    - {content} -
    - ) - } -) + return ( +
    + {content} +
    + ) +} Checkbox.displayName = 'Checkbox' diff --git a/packages/components/checkbox/src/CheckboxGroup.tsx b/packages/components/checkbox/src/CheckboxGroup.tsx index 01dd2d790..e44e43dcd 100644 --- a/packages/components/checkbox/src/CheckboxGroup.tsx +++ b/packages/components/checkbox/src/CheckboxGroup.tsx @@ -1,6 +1,6 @@ import { useFormFieldControl } from '@spark-ui/form-field' import { useCombinedState } from '@spark-ui/use-combined-state' -import { ComponentPropsWithoutRef, forwardRef, useEffect, useMemo, useRef } from 'react' +import { ComponentPropsWithoutRef, Ref, useEffect, useMemo, useRef } from 'react' import { checkboxGroupStyles, CheckboxGroupStylesProps } from './CheckboxGroup.styles' import { CheckboxGroupContext, CheckboxGroupContextState } from './CheckboxGroupContext' @@ -17,76 +17,73 @@ export interface CheckboxGroupProps * The callback fired when any children Checkbox is checked or unchecked */ onCheckedChange?: (value: string[]) => void + ref?: Ref } -export const CheckboxGroup = forwardRef( - ( - { - name: nameProp, - value: valueProp, - defaultValue, - className, - intent, - orientation = 'vertical', - onCheckedChange: onCheckedChangeProp, - reverse = false, - children, - ...others - }, - ref - ) => { - const [value, setValue] = useCombinedState(valueProp, defaultValue) - const field = useFormFieldControl() - const onCheckedChangeRef = useRef(onCheckedChangeProp) +export const CheckboxGroup = ({ + name: nameProp, + value: valueProp, + defaultValue, + className, + intent, + orientation = 'vertical', + onCheckedChange: onCheckedChangeProp, + reverse = false, + children, + ref, + ...others +}: CheckboxGroupProps) => { + const [value, setValue] = useCombinedState(valueProp, defaultValue) + const field = useFormFieldControl() + const onCheckedChangeRef = useRef(onCheckedChangeProp) - const { id, labelId, description, state, isInvalid, isRequired } = field - const name = nameProp ?? field.name + const { id, labelId, description, state, isInvalid, isRequired } = field + const name = nameProp ?? field.name - const current = useMemo(() => { - const handleCheckedChange = (checked: boolean, changed: string) => { - const values = value || [] - const modified = checked ? [...values, changed] : values.filter(val => val !== changed) + const current = useMemo(() => { + const handleCheckedChange = (checked: boolean, changed: string) => { + const values = value || [] + const modified = checked ? [...values, changed] : values.filter(val => val !== changed) - setValue(modified) + setValue(modified) - if (onCheckedChangeRef.current) { - onCheckedChangeRef.current(modified) - } + if (onCheckedChangeRef.current) { + onCheckedChangeRef.current(modified) } + } - return { - id, - name, - value, - intent, - state, - isInvalid, - description, - isRequired, - reverse, - onCheckedChange: handleCheckedChange, - } - }, [id, name, value, intent, state, isInvalid, description, isRequired, setValue, reverse]) + return { + id, + name, + value, + intent, + state, + isInvalid, + description, + isRequired, + reverse, + onCheckedChange: handleCheckedChange, + } + }, [id, name, value, intent, state, isInvalid, description, isRequired, setValue, reverse]) - useEffect(() => { - onCheckedChangeRef.current = onCheckedChangeProp - }, [onCheckedChangeProp]) + useEffect(() => { + onCheckedChangeRef.current = onCheckedChangeProp + }, [onCheckedChangeProp]) - return ( - -
    - {children} -
    -
    - ) - } -) + return ( + +
    + {children} +
    +
    + ) +} CheckboxGroup.displayName = 'CheckboxGroup' diff --git a/packages/components/checkbox/src/CheckboxIndicator.tsx b/packages/components/checkbox/src/CheckboxIndicator.tsx index cb992b516..b1a16e9de 100644 --- a/packages/components/checkbox/src/CheckboxIndicator.tsx +++ b/packages/components/checkbox/src/CheckboxIndicator.tsx @@ -2,18 +2,14 @@ import { CheckboxIndicator as CheckboxIndicatorPrimitive, CheckboxIndicatorProps as CheckboxIndicatorPrimitiveProps, } from '@radix-ui/react-checkbox' -import { forwardRef } from 'react' +import { Ref } from 'react' -export type CheckboxIndicatorProps = CheckboxIndicatorPrimitiveProps +export type CheckboxIndicatorProps = CheckboxIndicatorPrimitiveProps & { + ref?: Ref +} -export const CheckboxIndicator = forwardRef( - (props, ref) => ( - - ) +export const CheckboxIndicator = (props: CheckboxIndicatorProps) => ( + ) CheckboxIndicator.displayName = 'CheckboxIndicator' diff --git a/packages/components/checkbox/src/CheckboxInput.tsx b/packages/components/checkbox/src/CheckboxInput.tsx index 7af25070d..74d980416 100644 --- a/packages/components/checkbox/src/CheckboxInput.tsx +++ b/packages/components/checkbox/src/CheckboxInput.tsx @@ -2,7 +2,7 @@ import { Checkbox as CheckboxPrimitive } from '@radix-ui/react-checkbox' import { Icon } from '@spark-ui/icon' import { Check } from '@spark-ui/icons/dist/icons/Check' import { Minus } from '@spark-ui/icons/dist/icons/Minus' -import { ComponentPropsWithoutRef, forwardRef, ReactNode } from 'react' +import { ComponentPropsWithoutRef, ReactNode, Ref } from 'react' import { CheckboxIndicator } from './CheckboxIndicator' import { checkboxInputStyles, type CheckboxInputStylesProps } from './CheckboxInput.styles' @@ -48,24 +48,28 @@ export interface CheckboxInputProps * Event handler called when the checked state of the checkbox changes. */ onCheckedChange?: (checked: boolean) => void + ref?: Ref } -export const CheckboxInput = forwardRef( - ( - { className, icon = , indeterminateIcon = , intent, checked, ...others }, - ref - ) => ( - - - {checked === 'indeterminate' ? indeterminateIcon : icon} - - - ) +export const CheckboxInput = ({ + className, + icon = , + indeterminateIcon = , + intent, + checked, + ref, + ...others +}: CheckboxInputProps) => ( + + + {checked === 'indeterminate' ? indeterminateIcon : icon} + + ) CheckboxInput.displayName = 'CheckboxInput' diff --git a/packages/components/chip/CHANGELOG.md b/packages/components/chip/CHANGELOG.md index 8a1707237..a3a98e3c2 100644 --- a/packages/components/chip/CHANGELOG.md +++ b/packages/components/chip/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/chip + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/chip diff --git a/packages/components/chip/package.json b/packages/components/chip/package.json index 496d3067a..202ceb22d 100644 --- a/packages/components/chip/package.json +++ b/packages/components/chip/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/chip", - "version": "7.3.7", + "version": "8.0.0", "description": "To help people enter information, make selections, filter content, or trigger actions.", "publishConfig": { "access": "public" @@ -44,10 +44,10 @@ "homepage": "https://sparkui.vercel.app", "license": "MIT", "dependencies": { - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "emulate-tab": "^1.2.1" } } diff --git a/packages/components/chip/src/Chip.tsx b/packages/components/chip/src/Chip.tsx index 1f8d616ad..75e733a78 100644 --- a/packages/components/chip/src/Chip.tsx +++ b/packages/components/chip/src/Chip.tsx @@ -1,4 +1,4 @@ -import React, { ComponentPropsWithoutRef, forwardRef } from 'react' +import React, { ComponentPropsWithoutRef, Ref } from 'react' import { chipStyles, type ChipStylesProps } from './Chip.styles' import { ChipContext } from './useChipContext' @@ -30,65 +30,62 @@ export interface ChipProps extends ChipPrimitiveProps, Omit) => void + ref?: Ref } -export const Chip = forwardRef( - ( - { - design = 'outlined', - disabled, - children, - intent = 'basic', - defaultPressed, - pressed, - asChild, - className, - onClick, - onClear, - ...otherProps - }, - forwardedRef - ) => { - const { - Element: ChipElement, - chipProps: { children: formattedChildren, ...chipProps }, - compoundElements, - } = useChipElement({ - asChild, - pressed, - defaultPressed, - onClick, - disabled: !!disabled, - value: otherProps.value, - defaultValue: otherProps.defaultValue, - children, - onClear, - }) +export const Chip = ({ + design = 'outlined', + disabled, + children, + intent = 'basic', + defaultPressed, + pressed, + asChild, + className, + onClick, + onClear, + ref: forwardedRef, + ...otherProps +}: ChipProps) => { + const { + Element: ChipElement, + chipProps: { children: formattedChildren, ...chipProps }, + compoundElements, + } = useChipElement({ + asChild, + pressed, + defaultPressed, + onClick, + disabled: !!disabled, + value: otherProps.value, + defaultValue: otherProps.defaultValue, + children, + onClear, + }) - const { clearButton } = compoundElements + const { clearButton } = compoundElements - return ( - - - {formattedChildren} - - - ) - } -) + return ( + + + {formattedChildren} + + + ) +} Chip.displayName = 'Chip' diff --git a/packages/components/chip/src/ChipClearButton.tsx b/packages/components/chip/src/ChipClearButton.tsx index 254984d38..851d2abd9 100644 --- a/packages/components/chip/src/ChipClearButton.tsx +++ b/packages/components/chip/src/ChipClearButton.tsx @@ -1,6 +1,6 @@ import { Icon } from '@spark-ui/icon' import { Close } from '@spark-ui/icons/dist/icons/Close' -import React, { cloneElement, ComponentPropsWithoutRef, forwardRef, useCallback } from 'react' +import React, { cloneElement, ComponentPropsWithoutRef, Ref, useCallback } from 'react' import { chipClearButtonStyles, @@ -13,54 +13,51 @@ export interface ChipClearButtonProps extends ComponentPropsWithoutRef<'span'>, ChipClearButtonStylesProps { label: string + ref?: Ref } -export const ChipClearButton = forwardRef( - ( - { - children = ( - - - - ), - tabIndex = 0, - label, - }, - forwardedRef - ) => { - const { design, disabled, onClear } = useChipContext() +export const ChipClearButton = ({ + children = ( + + + + ), + tabIndex = 0, + label, + ref: forwardedRef, +}: ChipClearButtonProps) => { + const { design, disabled, onClear } = useChipContext() - const onClearHandler = useCallback( - (event: React.MouseEvent) => { - event.stopPropagation() - !disabled && onClear && onClear(event) - }, - [disabled, onClear] - ) + const onClearHandler = useCallback( + (event: React.MouseEvent) => { + event.stopPropagation() + !disabled && onClear && onClear(event) + }, + [disabled, onClear] + ) - return ( - + - - ) - } -) + {children && + cloneElement(children as React.ReactElement, { ariaLabel: label })} + + + ) +} ChipClearButton.displayName = 'Chip.ClearButton' diff --git a/packages/components/chip/src/ChipContent.tsx b/packages/components/chip/src/ChipContent.tsx index ab82d18a7..834bd8cf2 100644 --- a/packages/components/chip/src/ChipContent.tsx +++ b/packages/components/chip/src/ChipContent.tsx @@ -1,16 +1,16 @@ import { cx } from 'class-variance-authority' -import React, { ComponentPropsWithoutRef, forwardRef } from 'react' +import React, { ComponentPropsWithoutRef, Ref } from 'react' -export type ChipContentProps = ComponentPropsWithoutRef<'span'> +export type ChipContentProps = ComponentPropsWithoutRef<'span'> & { + ref?: Ref +} -export const ChipContent = forwardRef( - ({ children, className }, forwardedRef) => { - return ( - - {children} - - ) - } -) +export const ChipContent = ({ children, className, ref: forwardedRef }: ChipContentProps) => { + return ( + + {children} + + ) +} ChipContent.displayName = 'Chip.Content' diff --git a/packages/components/chip/src/ChipIcon.tsx b/packages/components/chip/src/ChipIcon.tsx index b67de5c72..3d0220e26 100644 --- a/packages/components/chip/src/ChipIcon.tsx +++ b/packages/components/chip/src/ChipIcon.tsx @@ -1,16 +1,16 @@ import { cx } from 'class-variance-authority' -import React, { ComponentPropsWithoutRef, forwardRef } from 'react' +import React, { ComponentPropsWithoutRef, Ref } from 'react' -export type ChipIconProps = ComponentPropsWithoutRef<'span'> +export type ChipIconProps = ComponentPropsWithoutRef<'span'> & { + ref?: Ref +} -export const ChipIcon = forwardRef>( - ({ children, className }, forwardedRef) => { - return ( - - {children} - - ) - } -) +export const ChipIcon = ({ children, className, ref: forwardedRef }: ChipIconProps) => { + return ( + + {children} + + ) +} ChipIcon.displayName = 'Chip.Icon' diff --git a/packages/components/chip/src/ChipLeadingIcon.tsx b/packages/components/chip/src/ChipLeadingIcon.tsx index 13b0d2e05..c22ed0481 100644 --- a/packages/components/chip/src/ChipLeadingIcon.tsx +++ b/packages/components/chip/src/ChipLeadingIcon.tsx @@ -1,14 +1,18 @@ import { cx } from 'class-variance-authority' -import React, { forwardRef } from 'react' +import React, { Ref } from 'react' import { ChipIcon, type ChipIconProps } from './ChipIcon' -export type ChipLeadingIconProps = ChipIconProps +export type ChipLeadingIconProps = ChipIconProps & { + ref?: Ref +} -export const ChipLeadingIcon = forwardRef( - ({ className, ...props }, forwardedRef) => ( - - ) +export const ChipLeadingIcon = ({ + className, + ref: forwardedRef, + ...props +}: ChipLeadingIconProps) => ( + ) ChipLeadingIcon.displayName = 'Chip.LeadingIcon' diff --git a/packages/components/chip/src/ChipTrailingIcon.tsx b/packages/components/chip/src/ChipTrailingIcon.tsx index ff5fcf4fe..abe18b6e9 100644 --- a/packages/components/chip/src/ChipTrailingIcon.tsx +++ b/packages/components/chip/src/ChipTrailingIcon.tsx @@ -1,14 +1,18 @@ import { cx } from 'class-variance-authority' -import React, { forwardRef } from 'react' +import React, { Ref } from 'react' import { ChipIcon, type ChipIconProps } from './ChipIcon' -export type ChipTrailingIconProps = ChipIconProps +export type ChipTrailingIconProps = ChipIconProps & { + ref?: Ref +} -export const ChipTrailingIcon = forwardRef( - ({ className, ...props }, forwardedRef) => ( - - ) +export const ChipTrailingIcon = ({ + className, + ref: forwardedRef, + ...props +}: ChipTrailingIconProps) => ( + ) ChipTrailingIcon.displayName = 'Chip.TrailingIcon' diff --git a/packages/components/collapsible/CHANGELOG.md b/packages/components/collapsible/CHANGELOG.md index 1126361d6..5cb51a015 100644 --- a/packages/components/collapsible/CHANGELOG.md +++ b/packages/components/collapsible/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/collapsible + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/collapsible diff --git a/packages/components/collapsible/package.json b/packages/components/collapsible/package.json index bc0696ced..5e5f12635 100644 --- a/packages/components/collapsible/package.json +++ b/packages/components/collapsible/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/collapsible", - "version": "7.3.7", + "version": "8.0.0", "description": "An interactive component which expands/collapses a panel.", "publishConfig": { "access": "public" @@ -45,8 +45,8 @@ "homepage": "https://sparkui.vercel.app", "license": "MIT", "dependencies": { - "@spark-ui/internal-utils": "^7.3.7", - "@spark-ui/slot": "^7.3.7", + "@spark-ui/internal-utils": "^8.0.0", + "@spark-ui/slot": "^8.0.0", "@zag-js/collapsible": "0.81.0", "@zag-js/react": "0.81.0" } diff --git a/packages/components/collapsible/src/Collapsible.tsx b/packages/components/collapsible/src/Collapsible.tsx index 7d601632d..359b61ecb 100644 --- a/packages/components/collapsible/src/Collapsible.tsx +++ b/packages/components/collapsible/src/Collapsible.tsx @@ -2,7 +2,7 @@ import { useEvent } from '@spark-ui/internal-utils' import { Slot } from '@spark-ui/slot' import * as collapsible from '@zag-js/collapsible' import { mergeProps, normalizeProps, type PropTypes, useMachine } from '@zag-js/react' -import { type ComponentProps, createContext, forwardRef, useContext, useId } from 'react' +import { type ComponentProps, createContext, Ref, useContext, useId } from 'react' export interface CollapsibleProps extends ComponentProps<'div'> { /** @@ -29,59 +29,56 @@ export interface CollapsibleProps extends ComponentProps<'div'> { * The ids of the elements in the collapsible. Useful for composition */ ids?: collapsible.Context['ids'] + ref?: Ref } const CollapsibleContext = createContext | null>(null) -export const Collapsible = forwardRef( - ( - { - asChild = false, - children, - defaultOpen = false, - disabled = false, - onOpenChange, - open, - ids, - ...props - }, - ref - ) => { - const initialContext: collapsible.Context = { - 'open.controlled': open !== undefined, - open: defaultOpen || open, - disabled, - id: useId(), - ids, - } +export const Collapsible = ({ + asChild = false, + children, + defaultOpen = false, + disabled = false, + onOpenChange, + open, + ids, + ref, + ...props +}: CollapsibleProps) => { + const initialContext: collapsible.Context = { + 'open.controlled': open !== undefined, + open: defaultOpen || open, + disabled, + id: useId(), + ids, + } - const context: collapsible.Context = { - ...initialContext, - onOpenChange: useEvent( - (details: collapsible.OpenChangeDetails) => { - onOpenChange?.(details.open) - }, - { sync: true } - ), - open, - disabled, - } + const context: collapsible.Context = { + ...initialContext, + onOpenChange: useEvent( + (details: collapsible.OpenChangeDetails) => { + onOpenChange?.(details.open) + }, + { sync: true } + ), + open, + disabled, + } - const [state, send] = useMachine(collapsible.machine(initialContext), { context }) - const api = collapsible.connect(state, send, normalizeProps) - const Component = asChild ? Slot : 'div' + const [state, send] = useMachine(collapsible.machine(initialContext), { context }) + const api = collapsible.connect(state, send, normalizeProps) + const Component = asChild ? Slot : 'div' - const mergedProps = mergeProps(api.getRootProps(), props) + const mergedProps = mergeProps(api.getRootProps(), props) - return ( - - - {children} - - - ) - } -) + return ( + + + {children} + + + ) +} Collapsible.displayName = 'Collapsible' diff --git a/packages/components/collapsible/src/CollapsibleContent.tsx b/packages/components/collapsible/src/CollapsibleContent.tsx index 82a530a3e..30435cf1e 100644 --- a/packages/components/collapsible/src/CollapsibleContent.tsx +++ b/packages/components/collapsible/src/CollapsibleContent.tsx @@ -1,37 +1,42 @@ import { Slot } from '@spark-ui/slot' import { mergeProps } from '@zag-js/react' import { cx } from 'class-variance-authority' -import { type ComponentPropsWithoutRef, forwardRef } from 'react' +import { type ComponentPropsWithoutRef, Ref } from 'react' import { useCollapsibleContext } from './Collapsible' export interface CollapsibleContentProps extends ComponentPropsWithoutRef<'div'> { asChild?: boolean + ref?: Ref } -export const Content = forwardRef( - ({ asChild = false, className, children, ...props }, ref) => { - const { getContentProps } = useCollapsibleContext() +export const Content = ({ + asChild = false, + className, + children, + ref, + ...props +}: CollapsibleContentProps) => { + const { getContentProps } = useCollapsibleContext() - const Component = asChild ? Slot : 'div' - const contentProps = getContentProps() - const mergedProps = mergeProps(contentProps, { - className: cx( - 'overflow-hidden', - 'motion-reduce:!animate-none', - '[&[hidden]]:hidden', - 'data-[state=open]:animate-standalone-collapse-in data-[state=closed]:animate-standalone-collapse-out', - className - ), - ...props, - }) + const Component = asChild ? Slot : 'div' + const contentProps = getContentProps() + const mergedProps = mergeProps(contentProps, { + className: cx( + 'overflow-hidden', + 'motion-reduce:!animate-none', + '[&[hidden]]:hidden', + 'data-[state=open]:animate-standalone-collapse-in data-[state=closed]:animate-standalone-collapse-out', + className + ), + ...props, + }) - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} Content.displayName = 'Collapsible.Content' diff --git a/packages/components/collapsible/src/CollapsibleTrigger.tsx b/packages/components/collapsible/src/CollapsibleTrigger.tsx index 1b5ce6193..78bdfa5a5 100644 --- a/packages/components/collapsible/src/CollapsibleTrigger.tsx +++ b/packages/components/collapsible/src/CollapsibleTrigger.tsx @@ -1,25 +1,24 @@ import { Slot } from '@spark-ui/slot' import { mergeProps } from '@zag-js/react' -import { type ComponentPropsWithoutRef, forwardRef } from 'react' +import { type ComponentPropsWithoutRef, Ref } from 'react' import { useCollapsibleContext } from './Collapsible' export interface CollapsibleTriggerProps extends ComponentPropsWithoutRef<'button'> { asChild?: boolean + ref?: Ref } -export const Trigger = forwardRef( - ({ asChild = false, children, ...props }, ref) => { - const collapsibleContext = useCollapsibleContext() - const Component = asChild ? Slot : 'button' - const mergedProps = mergeProps(collapsibleContext.getTriggerProps(), props) +export const Trigger = ({ asChild = false, children, ref, ...props }: CollapsibleTriggerProps) => { + const collapsibleContext = useCollapsibleContext() + const Component = asChild ? Slot : 'button' + const mergedProps = mergeProps(collapsibleContext.getTriggerProps(), props) - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} Trigger.displayName = 'Collapsible.Trigger' diff --git a/packages/components/combobox/CHANGELOG.md b/packages/components/combobox/CHANGELOG.md index ee053d16c..d8a0cd0a5 100644 --- a/packages/components/combobox/CHANGELOG.md +++ b/packages/components/combobox/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/combobox + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/combobox diff --git a/packages/components/combobox/package.json b/packages/components/combobox/package.json index c8a712b78..849c87d0f 100644 --- a/packages/components/combobox/package.json +++ b/packages/components/combobox/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/combobox", - "version": "7.3.7", + "version": "8.0.0", "description": "An input that behaves similarly to a select, with the addition of a free text input to filter options.", "publishConfig": { "access": "public" @@ -28,17 +28,17 @@ "tailwindcss": "^3.0.0" }, "devDependencies": { - "@spark-ui/dialog": "^7.3.7" + "@spark-ui/dialog": "^8.0.0" }, "dependencies": { - "@spark-ui/form-field": "^7.3.7", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", - "@spark-ui/popover": "^7.3.7", - "@spark-ui/spinner": "^7.3.7", - "@spark-ui/use-merge-refs": "^7.3.7", - "@spark-ui/visually-hidden": "^7.3.7", + "@spark-ui/form-field": "^8.0.0", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", + "@spark-ui/popover": "^8.0.0", + "@spark-ui/spinner": "^8.0.0", + "@spark-ui/use-merge-refs": "^8.0.0", + "@spark-ui/visually-hidden": "^8.0.0", "class-variance-authority": "0.7.0", "downshift": "9.0.7" }, diff --git a/packages/components/combobox/src/ComboboxClearButton.tsx b/packages/components/combobox/src/ComboboxClearButton.tsx index d81e85d5f..3f91d0462 100644 --- a/packages/components/combobox/src/ComboboxClearButton.tsx +++ b/packages/components/combobox/src/ComboboxClearButton.tsx @@ -1,53 +1,58 @@ import { Icon } from '@spark-ui/icon' import { DeleteOutline } from '@spark-ui/icons/dist/icons/DeleteOutline' import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef, MouseEventHandler } from 'react' +import { ComponentPropsWithoutRef, MouseEventHandler, Ref } from 'react' import { useComboboxContext } from './ComboboxContext' export interface ClearButtonProps extends ComponentPropsWithoutRef<'button'> { 'aria-label': string + ref?: Ref } -export const ClearButton = forwardRef( - ({ className, tabIndex = -1, onClick, ...others }, ref) => { - const ctx = useComboboxContext() - - const handleClick: MouseEventHandler = event => { - event.stopPropagation() - - if (ctx.multiple) { - ctx.setSelectedItems([]) - } else { - ctx.selectItem(null) - } - - ctx.setInputValue('') +export const ClearButton = ({ + className, + tabIndex = -1, + onClick, + ref, + ...others +}: ClearButtonProps) => { + const ctx = useComboboxContext() + + const handleClick: MouseEventHandler = event => { + event.stopPropagation() + + if (ctx.multiple) { + ctx.setSelectedItems([]) + } else { + ctx.selectItem(null) + } - if (ctx.innerInputRef.current) { - ctx.innerInputRef.current.focus() - } + ctx.setInputValue('') - if (onClick) { - onClick(event) - } + if (ctx.innerInputRef.current) { + ctx.innerInputRef.current.focus() } - return ( - - ) + if (onClick) { + onClick(event) + } } -) + + return ( + + ) +} ClearButton.displayName = 'Combobox.ClearButton' diff --git a/packages/components/combobox/src/ComboboxDisclosure.tsx b/packages/components/combobox/src/ComboboxDisclosure.tsx index ed08f8f9a..e076dd4fa 100644 --- a/packages/components/combobox/src/ComboboxDisclosure.tsx +++ b/packages/components/combobox/src/ComboboxDisclosure.tsx @@ -4,7 +4,7 @@ import { IconButton } from '@spark-ui/icon-button' import { ArrowHorizontalDown } from '@spark-ui/icons/dist/icons/ArrowHorizontalDown' import { useMergeRefs } from '@spark-ui/use-merge-refs' import { cx } from 'class-variance-authority' -import { ComponentProps, forwardRef, type Ref } from 'react' +import { ComponentProps, Ref } from 'react' import { useComboboxContext } from './ComboboxContext' @@ -12,55 +12,52 @@ interface DisclosureProps extends Omit, 'aria- className?: string closedLabel: string openedLabel: string + ref?: Ref } -export const Disclosure = forwardRef( - ( - { - className, - closedLabel, - openedLabel, - intent = 'neutral', - design = 'ghost', - size = 'sm', - ...props - }: DisclosureProps, - forwardedRef: Ref - ) => { - const ctx = useComboboxContext() +export const Disclosure = ({ + className, + closedLabel, + openedLabel, + intent = 'neutral', + design = 'ghost', + size = 'sm', + ref: forwardedRef, + ...props +}: DisclosureProps) => { + const ctx = useComboboxContext() - const { ref: downshiftRef, ...downshiftDisclosureProps } = ctx.getToggleButtonProps({ - disabled: ctx.disabled || ctx.readOnly, - onClick: event => { - event.stopPropagation() - }, - }) - const isExpanded = downshiftDisclosureProps['aria-expanded'] - const ref = useMergeRefs(forwardedRef, downshiftRef) + const { ref: downshiftRef, ...downshiftDisclosureProps } = ctx.getToggleButtonProps({ + disabled: ctx.disabled || ctx.readOnly, + onClick: event => { + event.stopPropagation() + }, + }) + const isExpanded = downshiftDisclosureProps['aria-expanded'] + const ref = useMergeRefs(forwardedRef, downshiftRef) - return ( - + - - - - - ) - } -) + + + + ) +} Disclosure.displayName = 'Combobox.Disclosure' diff --git a/packages/components/combobox/src/ComboboxEmpty.tsx b/packages/components/combobox/src/ComboboxEmpty.tsx index 08db7b428..b4533f7fa 100644 --- a/packages/components/combobox/src/ComboboxEmpty.tsx +++ b/packages/components/combobox/src/ComboboxEmpty.tsx @@ -1,27 +1,26 @@ import { cx } from 'class-variance-authority' -import { forwardRef, type ReactNode, type Ref } from 'react' +import { type ReactNode, Ref } from 'react' import { useComboboxContext } from './ComboboxContext' interface EmptyProps { className?: string children: ReactNode + ref?: Ref } -export const Empty = forwardRef( - ({ className, children }: EmptyProps, forwardedRef: Ref) => { - const ctx = useComboboxContext() - const hasNoItemVisible = ctx.filteredItemsMap.size === 0 +export const Empty = ({ className, children, ref: forwardedRef }: EmptyProps) => { + const ctx = useComboboxContext() + const hasNoItemVisible = ctx.filteredItemsMap.size === 0 - return hasNoItemVisible ? ( -
    - {children} -
    - ) : null - } -) + return hasNoItemVisible ? ( +
    + {children} +
    + ) : null +} Empty.displayName = 'Combobox.Empty' diff --git a/packages/components/combobox/src/ComboboxGroup.tsx b/packages/components/combobox/src/ComboboxGroup.tsx index 2d455da36..41ce39aea 100644 --- a/packages/components/combobox/src/ComboboxGroup.tsx +++ b/packages/components/combobox/src/ComboboxGroup.tsx @@ -1,5 +1,5 @@ import { cx } from 'class-variance-authority' -import React, { forwardRef, ReactNode, type Ref } from 'react' +import React, { ReactNode, Ref } from 'react' import { useComboboxContext } from './ComboboxContext' import { ComboboxGroupProvider, useComboboxGroupContext } from './ComboboxItemsGroupContext' @@ -7,43 +7,40 @@ import { ComboboxGroupProvider, useComboboxGroupContext } from './ComboboxItemsG interface GroupProps { children: ReactNode className?: string + ref?: Ref } -export const Group = forwardRef( - ({ children, ...props }: GroupProps, forwardedRef: Ref) => { - return ( - - - {children} - - - ) - } -) +export const Group = ({ children, ref: forwardedRef, ...props }: GroupProps) => { + return ( + + + {children} + + + ) +} -const GroupContent = forwardRef( - ({ children, className }: GroupProps, forwardedRef: Ref) => { - const ctx = useComboboxContext() - const groupCtx = useComboboxGroupContext() +const GroupContent = ({ children, className, ref: forwardedRef }: GroupProps) => { + const ctx = useComboboxContext() + const groupCtx = useComboboxGroupContext() - const hasVisibleOptions = React.Children.toArray(children).some(child => { - return ( - React.isValidElement(child) && - ctx.filteredItemsMap.get((child.props as { value: string }).value) - ) - }) + const hasVisibleOptions = React.Children.toArray(children).some(child => { + return ( + React.isValidElement(child) && + ctx.filteredItemsMap.get((child.props as { value: string }).value) + ) + }) - return hasVisibleOptions ? ( -
    - {children} -
    - ) : null - } -) + return hasVisibleOptions ? ( +
    + {children} +
    + ) : null +} Group.displayName = 'Combobox.Group' diff --git a/packages/components/combobox/src/ComboboxInput.tsx b/packages/components/combobox/src/ComboboxInput.tsx index 20e1436ba..de4a9df66 100644 --- a/packages/components/combobox/src/ComboboxInput.tsx +++ b/packages/components/combobox/src/ComboboxInput.tsx @@ -3,7 +3,7 @@ import { useCombinedState } from '@spark-ui/use-combined-state' import { useMergeRefs } from '@spark-ui/use-merge-refs' import { VisuallyHidden } from '@spark-ui/visually-hidden' import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef, Fragment, type Ref, useEffect } from 'react' +import { ComponentPropsWithoutRef, Fragment, Ref, useEffect } from 'react' import { useComboboxContext } from './ComboboxContext' @@ -15,99 +15,96 @@ interface InputProps extends Omit value?: string defaultValue?: string onValueChange?: (value: string) => void + ref?: Ref } -export const Input = forwardRef( - ( - { - 'aria-label': ariaLabel, - className, - placeholder, - value, - defaultValue, - onValueChange, - ...props - }: InputProps, - forwardedRef: Ref - ) => { - const ctx = useComboboxContext() - const [inputValue] = useCombinedState(value, defaultValue) +export const Input = ({ + 'aria-label': ariaLabel, + className, + placeholder, + value, + defaultValue, + onValueChange, + ref: forwardedRef, + ...props +}: InputProps) => { + const ctx = useComboboxContext() + const [inputValue] = useCombinedState(value, defaultValue) - useEffect(() => { - if (inputValue != null) { - ctx.setInputValue(inputValue) - } - }, [inputValue]) + useEffect(() => { + if (inputValue != null) { + ctx.setInputValue(inputValue) + } + }, [inputValue]) - useEffect(() => { - if (onValueChange) { - ctx.setOnInputValueChange(() => onValueChange) - } + useEffect(() => { + if (onValueChange) { + ctx.setOnInputValueChange(() => onValueChange) + } - // Sync input with combobox default value - if (!ctx.multiple && ctx.selectedItem) { - ctx.setInputValue(ctx.selectedItem.text) - } - }, []) + // Sync input with combobox default value + if (!ctx.multiple && ctx.selectedItem) { + ctx.setInputValue(ctx.selectedItem.text) + } + }, []) - const [PopoverTrigger, popoverTriggerProps] = ctx.hasPopover - ? [Popover.Trigger, { asChild: true, type: undefined }] - : [Fragment, {}] + const [PopoverTrigger, popoverTriggerProps] = ctx.hasPopover + ? [Popover.Trigger, { asChild: true, type: undefined }] + : [Fragment, {}] - const multiselectInputProps = ctx.getDropdownProps() - const inputRef = useMergeRefs(forwardedRef, ctx.innerInputRef, multiselectInputProps.ref) - const downshiftInputProps = ctx.getInputProps({ - disabled: ctx.disabled || ctx.readOnly, - ...multiselectInputProps, - onKeyDown: event => { - multiselectInputProps.onKeyDown?.(event) - ctx.setLastInteractionType('keyboard') - ctx.setIsTyping(true) - }, - /** - * - * Important: - * - without this, the input cursor is moved to the end after every change. - * @see https://github.com/downshift-js/downshift/issues/1108#issuecomment-674180157 - */ - onChange: (e: React.ChangeEvent) => { - ctx.setInputValue(e.target.value) - }, - ref: inputRef, - }) + const multiselectInputProps = ctx.getDropdownProps() + const inputRef = useMergeRefs(forwardedRef, ctx.innerInputRef, multiselectInputProps.ref) + const downshiftInputProps = ctx.getInputProps({ + disabled: ctx.disabled || ctx.readOnly, + ...multiselectInputProps, + onKeyDown: event => { + multiselectInputProps.onKeyDown?.(event) + ctx.setLastInteractionType('keyboard') + ctx.setIsTyping(true) + }, + /** + * + * Important: + * - without this, the input cursor is moved to the end after every change. + * @see https://github.com/downshift-js/downshift/issues/1108#issuecomment-674180157 + */ + onChange: (e: React.ChangeEvent) => { + ctx.setInputValue(e.target.value) + }, + ref: inputRef, + }) - const hasPlaceholder = ctx.multiple ? ctx.selectedItems.length === 0 : ctx.selectedItem === null + const hasPlaceholder = ctx.multiple ? ctx.selectedItems.length === 0 : ctx.selectedItem === null - return ( - <> - {ariaLabel && ( - - - - )} - - - - - ) - } -) + return ( + <> + {ariaLabel && ( + + + + )} + + + + + ) +} Input.displayName = 'Combobox.Input' diff --git a/packages/components/combobox/src/ComboboxItem.tsx b/packages/components/combobox/src/ComboboxItem.tsx index 08deeda13..46aaaad94 100644 --- a/packages/components/combobox/src/ComboboxItem.tsx +++ b/packages/components/combobox/src/ComboboxItem.tsx @@ -1,6 +1,6 @@ import { useMergeRefs } from '@spark-ui/use-merge-refs' import { cva, cx } from 'class-variance-authority' -import { forwardRef, type HTMLAttributes, type ReactNode, type Ref } from 'react' +import { type HTMLAttributes, type ReactNode, Ref } from 'react' import { useComboboxContext } from './ComboboxContext' import { ComboboxItemProvider, useComboboxItemContext } from './ComboboxItemContext' @@ -10,21 +10,20 @@ export interface ItemProps extends HTMLAttributes { value: string children: ReactNode className?: string + ref?: Ref } -export const Item = forwardRef( - ({ children, ...props }: ItemProps, forwardedRef: Ref) => { - const { value, disabled } = props +export const Item = ({ children, ref: forwardedRef, ...props }: ItemProps) => { + const { value, disabled } = props - return ( - - - {children} - - - ) - } -) + return ( + + + {children} + + + ) +} const styles = cva('px-lg py-md text-body-1', { variants: { @@ -57,46 +56,47 @@ const styles = cva('px-lg py-md text-body-1', { ], }) -const ItemContent = forwardRef( - ( - { className, disabled = false, value, children }: ItemProps, - forwardedRef: Ref - ) => { - const ctx = useComboboxContext() - const itemCtx = useComboboxItemContext() +const ItemContent = ({ + className, + disabled = false, + value, + children, + ref: forwardedRef, +}: ItemProps) => { + const ctx = useComboboxContext() + const itemCtx = useComboboxItemContext() - const isVisible = !!ctx.filteredItemsMap.get(value) + const isVisible = !!ctx.filteredItemsMap.get(value) - const { ref: downshiftRef, ...downshiftItemProps } = ctx.getItemProps({ - item: itemCtx.itemData, - index: itemCtx.index, - }) + const { ref: downshiftRef, ...downshiftItemProps } = ctx.getItemProps({ + item: itemCtx.itemData, + index: itemCtx.index, + }) - const ref = useMergeRefs(forwardedRef, downshiftRef) + const ref = useMergeRefs(forwardedRef, downshiftRef) - if (!isVisible) return null + if (!isVisible) return null - return ( -
  • - {children} -
  • - ) - } -) + return ( +
  • + {children} +
  • + ) +} Item.displayName = 'Combobox.Item' diff --git a/packages/components/combobox/src/ComboboxItemIndicator.tsx b/packages/components/combobox/src/ComboboxItemIndicator.tsx index 51d44c801..dde871315 100644 --- a/packages/components/combobox/src/ComboboxItemIndicator.tsx +++ b/packages/components/combobox/src/ComboboxItemIndicator.tsx @@ -1,7 +1,7 @@ import { Icon } from '@spark-ui/icon' import { Check } from '@spark-ui/icons/dist/icons/Check' import { cx } from 'class-variance-authority' -import { forwardRef, ReactNode, type Ref } from 'react' +import { ReactNode, Ref } from 'react' import { useComboboxItemContext } from './ComboboxItemContext' @@ -9,27 +9,31 @@ export interface ItemIndicatorProps { children?: ReactNode className?: string label?: string + ref?: Ref } -export const ItemIndicator = forwardRef( - ({ className, children, label }: ItemIndicatorProps, forwardedRef: Ref) => { - const { disabled, isSelected } = useComboboxItemContext() +export const ItemIndicator = ({ + className, + children, + label, + ref: forwardedRef, +}: ItemIndicatorProps) => { + const { disabled, isSelected } = useComboboxItemContext() - const childElement = children || ( - - - - ) + const childElement = children || ( + + + + ) - return ( - - {isSelected && childElement} - - ) - } -) + return ( + + {isSelected && childElement} + + ) +} ItemIndicator.displayName = 'Combobox.ItemIndicator' diff --git a/packages/components/combobox/src/ComboboxItemText.tsx b/packages/components/combobox/src/ComboboxItemText.tsx index 782c6154a..4f28bee24 100644 --- a/packages/components/combobox/src/ComboboxItemText.tsx +++ b/packages/components/combobox/src/ComboboxItemText.tsx @@ -1,5 +1,5 @@ import { cx } from 'class-variance-authority' -import { forwardRef, type Ref, useEffect, useId } from 'react' +import { Ref, useEffect, useId } from 'react' import { ID_PREFIX } from './ComboboxContext' import { useComboboxItemContext } from './ComboboxItemContext' @@ -7,26 +7,25 @@ import { useComboboxItemContext } from './ComboboxItemContext' export interface ItemTextProps { children: string className?: string + ref?: Ref } -export const ItemText = forwardRef( - ({ children, className }: ItemTextProps, forwardedRef: Ref) => { - const id = `${ID_PREFIX}-item-text-${useId()}` +export const ItemText = ({ children, className, ref: forwardedRef }: ItemTextProps) => { + const id = `${ID_PREFIX}-item-text-${useId()}` - const { setTextId } = useComboboxItemContext() + const { setTextId } = useComboboxItemContext() - useEffect(() => { - setTextId(id) + useEffect(() => { + setTextId(id) - return () => setTextId(undefined) - }) + return () => setTextId(undefined) + }) - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} ItemText.displayName = 'Combobox.ItemText' diff --git a/packages/components/combobox/src/ComboboxItems.tsx b/packages/components/combobox/src/ComboboxItems.tsx index 7468c549a..78f0d98bb 100644 --- a/packages/components/combobox/src/ComboboxItems.tsx +++ b/packages/components/combobox/src/ComboboxItems.tsx @@ -1,66 +1,58 @@ import { Spinner } from '@spark-ui/spinner' import { useMergeRefs } from '@spark-ui/use-merge-refs' import { cx } from 'class-variance-authority' -import { - ComponentPropsWithoutRef, - forwardRef, - ReactNode, - type Ref, - useLayoutEffect, - useRef, -} from 'react' +import { ComponentPropsWithoutRef, ReactNode, Ref, useLayoutEffect, useRef } from 'react' import { useComboboxContext } from './ComboboxContext' interface ItemsProps extends ComponentPropsWithoutRef<'ul'> { children: ReactNode className?: string + ref?: Ref } -export const Items = forwardRef( - ({ children, className, ...props }: ItemsProps, forwardedRef: Ref) => { - const ctx = useComboboxContext() - - const { ref: downshiftRef, ...downshiftMenuProps } = ctx.getMenuProps({ - onMouseMove: () => { - ctx.setLastInteractionType('mouse') - }, - }) - - const innerRef = useRef(null) - - const ref = useMergeRefs(forwardedRef, downshiftRef, innerRef) - - const isOpen = ctx.hasPopover ? ctx.isOpen : true - - const isPointerEventsDisabled = ctx.hasPopover && !isOpen - - useLayoutEffect(() => { - if (innerRef.current?.parentElement) { - innerRef.current.parentElement.style.pointerEvents = isPointerEventsDisabled ? 'none' : '' - innerRef.current.style.pointerEvents = isPointerEventsDisabled ? 'none' : '' - } - }, [isPointerEventsDisabled]) - - return ( -
      - {ctx.isLoading ? : children} -
    - ) - } -) +export const Items = ({ children, className, ref: forwardedRef, ...props }: ItemsProps) => { + const ctx = useComboboxContext() + + const { ref: downshiftRef, ...downshiftMenuProps } = ctx.getMenuProps({ + onMouseMove: () => { + ctx.setLastInteractionType('mouse') + }, + }) + + const innerRef = useRef(null) + + const ref = useMergeRefs(forwardedRef, downshiftRef, innerRef) + + const isOpen = ctx.hasPopover ? ctx.isOpen : true + + const isPointerEventsDisabled = ctx.hasPopover && !isOpen + + useLayoutEffect(() => { + if (innerRef.current?.parentElement) { + innerRef.current.parentElement.style.pointerEvents = isPointerEventsDisabled ? 'none' : '' + innerRef.current.style.pointerEvents = isPointerEventsDisabled ? 'none' : '' + } + }, [isPointerEventsDisabled]) + + return ( +
      + {ctx.isLoading ? : children} +
    + ) +} Items.displayName = 'Combobox.Items' diff --git a/packages/components/combobox/src/ComboboxLabel.tsx b/packages/components/combobox/src/ComboboxLabel.tsx index 432eb4a68..c9e798343 100644 --- a/packages/components/combobox/src/ComboboxLabel.tsx +++ b/packages/components/combobox/src/ComboboxLabel.tsx @@ -1,27 +1,26 @@ import { cx } from 'class-variance-authority' -import { forwardRef, type Ref } from 'react' +import { Ref } from 'react' import { useComboboxGroupContext } from './ComboboxItemsGroupContext' interface LabelProps { children: string className?: string + ref?: Ref } -export const Label = forwardRef( - ({ children, className }: LabelProps, forwardedRef: Ref) => { - const groupCtx = useComboboxGroupContext() +export const Label = ({ children, className, ref: forwardedRef }: LabelProps) => { + const groupCtx = useComboboxGroupContext() - return ( -
    - {children} -
    - ) - } -) + return ( +
    + {children} +
    + ) +} Label.displayName = 'Combobox.Label' diff --git a/packages/components/combobox/src/ComboboxPopover.tsx b/packages/components/combobox/src/ComboboxPopover.tsx index 88d406369..667d7b1ea 100644 --- a/packages/components/combobox/src/ComboboxPopover.tsx +++ b/packages/components/combobox/src/ComboboxPopover.tsx @@ -1,50 +1,50 @@ import { Popover as SparkPopover } from '@spark-ui/popover' import { cx } from 'class-variance-authority' -import { ComponentProps, forwardRef, Ref, useEffect } from 'react' +import { ComponentProps, Ref, useEffect } from 'react' import { useComboboxContext } from './ComboboxContext' -export const Popover = forwardRef( - ( - { - children, - matchTriggerWidth = true, - sideOffset = 4, - className, - ...props - }: ComponentProps, - forwardedRef: Ref - ) => { - const ctx = useComboboxContext() +interface PopoverProps extends ComponentProps { + ref?: Ref +} - useEffect(() => { - ctx.setHasPopover(true) +export const Popover = ({ + children, + matchTriggerWidth = true, + sideOffset = 4, + className, + ref: forwardedRef, + ...props +}: PopoverProps) => { + const ctx = useComboboxContext() - return () => ctx.setHasPopover(false) - }, []) + useEffect(() => { + ctx.setHasPopover(true) - return ( - { - /** - * With a combobox pattern, the focus should remain on the trigger at all times. - * Passing the focus to the combobox popover would break keyboard navigation. - */ - e.preventDefault() - }} - {...props} - data-spark-component="combobox-popover" - > - {children} - - ) - } -) + return () => ctx.setHasPopover(false) + }, []) + + return ( + { + /** + * With a combobox pattern, the focus should remain on the trigger at all times. + * Passing the focus to the combobox popover would break keyboard navigation. + */ + e.preventDefault() + }} + {...props} + data-spark-component="combobox-popover" + > + {children} + + ) +} Popover.displayName = 'Combobox.Popover' diff --git a/packages/components/combobox/src/ComboboxTrigger.tsx b/packages/components/combobox/src/ComboboxTrigger.tsx index 15e00b3ee..13ce4766c 100644 --- a/packages/components/combobox/src/ComboboxTrigger.tsx +++ b/packages/components/combobox/src/ComboboxTrigger.tsx @@ -2,7 +2,7 @@ import { useFormFieldControl } from '@spark-ui/form-field' import { Popover } from '@spark-ui/popover' import { useMergeRefs } from '@spark-ui/use-merge-refs' import { cx } from 'class-variance-authority' -import React, { forwardRef, Fragment, ReactNode, type Ref, useEffect, useRef } from 'react' +import React, { Fragment, ReactNode, Ref, useEffect, useRef } from 'react' import { useComboboxContext } from './ComboboxContext' import { styles } from './ComboboxTrigger.styles' @@ -12,102 +12,101 @@ import { useWidthIncreaseCallback } from './utils/useWidthIncreaseCallback' interface TriggerProps { className?: string children: ReactNode + ref?: Ref } -export const Trigger = forwardRef( - ({ className, children }: TriggerProps, forwardedRef: Ref) => { - const ctx = useComboboxContext() - const field = useFormFieldControl() - - // Trigger compound elements - const leadingIcon = findElement(children, 'Combobox.LeadingIcon') - const selectedItems = findElement(children, 'Combobox.SelectedItems') - const input = findElement(children, 'Combobox.Input') - const clearButton = findElement(children, 'Combobox.ClearButton') - const disclosure = findElement(children, 'Combobox.Disclosure') - - const [PopoverAnchor, popoverAnchorProps] = ctx.hasPopover - ? [Popover.Anchor, { asChild: true, type: undefined }] - : [Fragment, {}] - - const ref = useMergeRefs(forwardedRef, ctx.triggerAreaRef) - const scrollableAreaRef = useRef(null) - - const disabled = field.disabled || ctx.disabled - const readOnly = field.readOnly || ctx.readOnly - - const hasClearButton = !!clearButton && !disabled && !readOnly - - /** - * In case wrap behaviour is disabled, we sometimes need to scroll to the right-side of the trigger: - * - when a selected item chip is added. - * - when the component width changes (window resizing, etc.) - * - * The goal is that the typing area remains visible at all times. - */ - const scrollToRight = () => { - if (scrollableAreaRef.current && !ctx.wrap) { - const { scrollWidth, clientWidth } = scrollableAreaRef.current - // Scroll to the rightmost position - scrollableAreaRef.current.scrollLeft = scrollWidth - clientWidth - } +export const Trigger = ({ className, children, ref: forwardedRef }: TriggerProps) => { + const ctx = useComboboxContext() + const field = useFormFieldControl() + + // Trigger compound elements + const leadingIcon = findElement(children, 'Combobox.LeadingIcon') + const selectedItems = findElement(children, 'Combobox.SelectedItems') + const input = findElement(children, 'Combobox.Input') + const clearButton = findElement(children, 'Combobox.ClearButton') + const disclosure = findElement(children, 'Combobox.Disclosure') + + const [PopoverAnchor, popoverAnchorProps] = ctx.hasPopover + ? [Popover.Anchor, { asChild: true, type: undefined }] + : [Fragment, {}] + + const ref = useMergeRefs(forwardedRef, ctx.triggerAreaRef) + const scrollableAreaRef = useRef(null) + + const disabled = field.disabled || ctx.disabled + const readOnly = field.readOnly || ctx.readOnly + + const hasClearButton = !!clearButton && !disabled && !readOnly + + /** + * In case wrap behaviour is disabled, we sometimes need to scroll to the right-side of the trigger: + * - when a selected item chip is added. + * - when the component width changes (window resizing, etc.) + * + * The goal is that the typing area remains visible at all times. + */ + const scrollToRight = () => { + if (scrollableAreaRef.current && !ctx.wrap) { + const { scrollWidth, clientWidth } = scrollableAreaRef.current + // Scroll to the rightmost position + scrollableAreaRef.current.scrollLeft = scrollWidth - clientWidth } + } - useWidthIncreaseCallback(scrollableAreaRef, scrollToRight) - - useEffect(() => { - const resizeObserver = new ResizeObserver(scrollToRight) + useWidthIncreaseCallback(scrollableAreaRef, scrollToRight) - if (scrollableAreaRef.current) { - resizeObserver.observe(scrollableAreaRef.current) - } + useEffect(() => { + const resizeObserver = new ResizeObserver(scrollToRight) - return () => { - resizeObserver.disconnect() - } - }, []) + if (scrollableAreaRef.current) { + resizeObserver.observe(scrollableAreaRef.current) + } - return ( - <> - -
    { - if (!ctx.isOpen && !disabled && !readOnly) { - ctx.openMenu() - if (ctx.innerInputRef.current) { - ctx.innerInputRef.current.focus() - } + return () => { + resizeObserver.disconnect() + } + }, []) + + return ( + <> + +
    { + if (!ctx.isOpen && !disabled && !readOnly) { + ctx.openMenu() + if (ctx.innerInputRef.current) { + ctx.innerInputRef.current.focus() } - }} + } + }} + > + {leadingIcon} +
    - {leadingIcon} -
    - {selectedItems} - {input} -
    - - {hasClearButton && clearButton} - - {disclosure} + {selectedItems} + {input}
    - - - ) - } -) + + {hasClearButton && clearButton} + + {disclosure} +
    +
    + + ) +} Trigger.displayName = 'Combobox.Trigger' diff --git a/packages/components/dialog/CHANGELOG.md b/packages/components/dialog/CHANGELOG.md index 55e3b48bd..6cb031c25 100644 --- a/packages/components/dialog/CHANGELOG.md +++ b/packages/components/dialog/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/dialog + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/dialog diff --git a/packages/components/dialog/package.json b/packages/components/dialog/package.json index d25bc7a09..6ade45978 100644 --- a/packages/components/dialog/package.json +++ b/packages/components/dialog/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/dialog", - "version": "7.3.7", + "version": "8.0.0", "description": "A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.", "publishConfig": { "access": "public" @@ -45,9 +45,9 @@ "license": "MIT", "dependencies": { "@radix-ui/react-dialog": "1.1.2", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" } } diff --git a/packages/components/dialog/src/DialogBody.tsx b/packages/components/dialog/src/DialogBody.tsx index b9d78f073..3e705fb4c 100644 --- a/packages/components/dialog/src/DialogBody.tsx +++ b/packages/components/dialog/src/DialogBody.tsx @@ -1,21 +1,23 @@ -import { forwardRef, type ReactElement, type ReactNode, type Ref } from 'react' +import { type ReactElement, type ReactNode, Ref } from 'react' import { dialogBodyStyles, type DialogBodyStylesProps } from './DialogBody.styles' export interface BodyProps extends DialogBodyStylesProps { children: ReactNode className?: string tabIndex?: number + ref?: Ref } -export const Body = forwardRef( - ( - { children, className, inset = false, ...rest }: BodyProps, - ref: Ref - ): ReactElement => ( -
    - {children} -
    - ) +export const Body = ({ + children, + className, + inset = false, + ref, + ...rest +}: BodyProps): ReactElement => ( +
    + {children} +
    ) Body.displayName = 'Dialog.Body' diff --git a/packages/components/dialog/src/DialogClose.tsx b/packages/components/dialog/src/DialogClose.tsx index 2b8a3c811..c33eaa9d3 100644 --- a/packages/components/dialog/src/DialogClose.tsx +++ b/packages/components/dialog/src/DialogClose.tsx @@ -1,11 +1,10 @@ import * as RadixDialog from '@radix-ui/react-dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -type CloseElement = ElementRef -export type CloseProps = RadixDialog.DialogCloseProps +export type CloseProps = RadixDialog.DialogCloseProps & { + ref?: Ref +} -export const Close = forwardRef((props, ref) => ( - -)) +export const Close = (props: CloseProps) => Close.displayName = 'Dialog.Close' diff --git a/packages/components/dialog/src/DialogCloseButton.tsx b/packages/components/dialog/src/DialogCloseButton.tsx index 1ce9a3029..56bfe8430 100644 --- a/packages/components/dialog/src/DialogCloseButton.tsx +++ b/packages/components/dialog/src/DialogCloseButton.tsx @@ -2,45 +2,39 @@ import { Icon } from '@spark-ui/icon' import { IconButton, type IconButtonProps } from '@spark-ui/icon-button' import { Close as CloseSVG } from '@spark-ui/icons/dist/icons/Close' import { cx } from 'class-variance-authority' -import { ElementRef, forwardRef } from 'react' import { Close, CloseProps } from './DialogClose' -type CloseButtonElement = ElementRef export type CloseButtonProps = CloseProps & Pick -const Root = forwardRef( - ( - { - 'aria-label': ariaLabel, - className, - size = 'md', - intent = 'neutral', - design = 'ghost', - children = , - ...rest - }, - ref - ) => { - return ( - - - {children} - - - ) - } -) +const Root = ({ + 'aria-label': ariaLabel, + className, + size = 'md', + intent = 'neutral', + design = 'ghost', + children = , + ref, + ...rest +}: CloseButtonProps) => { + return ( + + + {children} + + + ) +} export const CloseButton = Object.assign(Root, { id: 'CloseButton', }) -CloseButton.displayName = 'Dialog.CloseButton' +Root.displayName = 'Dialog.CloseButton' diff --git a/packages/components/dialog/src/DialogContent.tsx b/packages/components/dialog/src/DialogContent.tsx index 1d36c0468..5ba02504d 100644 --- a/packages/components/dialog/src/DialogContent.tsx +++ b/packages/components/dialog/src/DialogContent.tsx @@ -1,5 +1,5 @@ import * as RadixDialog from '@radix-ui/react-dialog' -import { forwardRef, type ReactElement, type Ref, useEffect } from 'react' +import { type ReactElement, Ref, useEffect } from 'react' import { dialogContentStyles, type DialogContentStylesProps } from './DialogContent.styles' import { useDialog } from './DialogContext' @@ -9,58 +9,55 @@ export interface ContentProps extends RadixDialog.DialogContentProps, DialogCont * When set to true, the content will adjust its width to fit the content rather than taking up the full available width. */ isNarrow?: boolean + ref?: Ref } -export const Content = forwardRef( - ( - { - children, - className, - isNarrow = false, - size = 'md', - onInteractOutside, - ...rest - }: ContentProps, - ref: Ref - ): ReactElement => { - const { setIsFullScreen } = useDialog() - - useEffect(() => { - if (size === 'fullscreen') setIsFullScreen(true) - - return () => setIsFullScreen(false) - }, [setIsFullScreen, size]) - - return ( - { - const isForegroundElement = (e.target as HTMLElement).closest('.z-toast, .z-popover') - - /** - * The focus trap of the dialog applies `pointer-events-none` on the body of the page in the background, but - * some components with an higher z-index have `pointer-events-auto` applied on them to remain interactive and ignore the focust trap (ex: a Snackbar with actions). - * - * Clicking on the snackbar will be considered as an "outside click" and close the dialog. We want to prevent this. - */ - if (isForegroundElement) { - e.preventDefault() - } - - onInteractOutside?.(e) - }} - {...rest} - > - {children} - - ) - } -) +export const Content = ({ + children, + className, + isNarrow = false, + size = 'md', + onInteractOutside, + ref, + ...rest +}: ContentProps): ReactElement => { + const { setIsFullScreen } = useDialog() + + useEffect(() => { + if (size === 'fullscreen') setIsFullScreen(true) + + return () => setIsFullScreen(false) + }, [setIsFullScreen, size]) + + return ( + { + const isForegroundElement = (e.target as HTMLElement).closest('.z-toast, .z-popover') + + /** + * The focus trap of the dialog applies `pointer-events-none` on the body of the page in the background, but + * some components with an higher z-index have `pointer-events-auto` applied on them to remain interactive and ignore the focust trap (ex: a Snackbar with actions). + * + * Clicking on the snackbar will be considered as an "outside click" and close the dialog. We want to prevent this. + */ + if (isForegroundElement) { + e.preventDefault() + } + + onInteractOutside?.(e) + }} + {...rest} + > + {children} + + ) +} Content.displayName = 'Dialog.Content' diff --git a/packages/components/dialog/src/DialogDescription.tsx b/packages/components/dialog/src/DialogDescription.tsx index 98809349c..eedb3a0d6 100644 --- a/packages/components/dialog/src/DialogDescription.tsx +++ b/packages/components/dialog/src/DialogDescription.tsx @@ -1,11 +1,10 @@ import * as RadixDialog from '@radix-ui/react-dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type DescriptionElement = ElementRef -export type DescriptionProps = RadixDialog.DialogDescriptionProps +export type DescriptionProps = RadixDialog.DialogDescriptionProps & { + ref?: Ref +} -export const Description = forwardRef((props, ref) => ( - -)) +export const Description = (props: DescriptionProps) => Description.displayName = 'Dialog.Description' diff --git a/packages/components/dialog/src/DialogFooter.tsx b/packages/components/dialog/src/DialogFooter.tsx index 3bf35b9eb..6253ed5b6 100644 --- a/packages/components/dialog/src/DialogFooter.tsx +++ b/packages/components/dialog/src/DialogFooter.tsx @@ -1,17 +1,16 @@ import { cx } from 'class-variance-authority' -import { forwardRef, type ReactElement, type ReactNode, type Ref } from 'react' +import { type ReactElement, type ReactNode, Ref } from 'react' export interface FooterProps { children: ReactNode className?: string + ref?: Ref } -export const Footer = forwardRef( - ({ children, className, ...rest }: FooterProps, ref: Ref): ReactElement => ( -
    - {children} -
    - ) +export const Footer = ({ children, className, ref, ...rest }: FooterProps): ReactElement => ( +
    + {children} +
    ) Footer.displayName = 'Dialog.Footer' diff --git a/packages/components/dialog/src/DialogHeader.tsx b/packages/components/dialog/src/DialogHeader.tsx index de0d43bbf..54576cef3 100644 --- a/packages/components/dialog/src/DialogHeader.tsx +++ b/packages/components/dialog/src/DialogHeader.tsx @@ -1,17 +1,16 @@ import { cx } from 'class-variance-authority' -import { forwardRef, type ReactElement, type ReactNode, type Ref } from 'react' +import { type ReactElement, type ReactNode, Ref } from 'react' export interface HeaderProps { children: ReactNode className?: string + ref?: Ref } -export const Header = forwardRef( - ({ children, className, ...rest }: HeaderProps, ref: Ref): ReactElement => ( -
    - {children} -
    - ) +export const Header = ({ children, className, ref, ...rest }: HeaderProps): ReactElement => ( +
    + {children} +
    ) Header.displayName = 'Dialog.Header' diff --git a/packages/components/dialog/src/DialogOverlay.tsx b/packages/components/dialog/src/DialogOverlay.tsx index 6e76009fc..c2a08b74a 100644 --- a/packages/components/dialog/src/DialogOverlay.tsx +++ b/packages/components/dialog/src/DialogOverlay.tsx @@ -1,30 +1,30 @@ import * as RadixDialog from '@radix-ui/react-dialog' import { cx } from 'class-variance-authority' -import { forwardRef, type ReactElement, type Ref } from 'react' +import { type ReactElement, Ref } from 'react' import { useDialog } from './DialogContext' -export type OverlayProps = RadixDialog.DialogOverlayProps +export type OverlayProps = RadixDialog.DialogOverlayProps & { + ref?: Ref +} -export const Overlay = forwardRef( - ({ className, ...rest }: OverlayProps, ref: Ref): ReactElement | null => { - const { isFullScreen } = useDialog() +export const Overlay = ({ className, ref, ...rest }: OverlayProps): ReactElement | null => { + const { isFullScreen } = useDialog() - return ( - - ) - } -) + return ( + + ) +} Overlay.displayName = 'Dialog.Overlay' diff --git a/packages/components/dialog/src/DialogTitle.tsx b/packages/components/dialog/src/DialogTitle.tsx index 9baaa795d..8d29ae773 100644 --- a/packages/components/dialog/src/DialogTitle.tsx +++ b/packages/components/dialog/src/DialogTitle.tsx @@ -1,11 +1,12 @@ import * as RadixDialog from '@radix-ui/react-dialog' import { cx } from 'class-variance-authority' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type TitleElement = ElementRef -export type TitleProps = RadixDialog.DialogTitleProps +export type TitleProps = RadixDialog.DialogTitleProps & { + ref?: Ref +} -export const Title = forwardRef(({ className, ...others }, ref) => { +export const Title = ({ className, ref, ...others }: TitleProps) => { return ( (({ className, ...other {...others} /> ) -}) +} Title.displayName = 'Dialog.Title' diff --git a/packages/components/dialog/src/DialogTrigger.tsx b/packages/components/dialog/src/DialogTrigger.tsx index 5d5243908..e9923b509 100644 --- a/packages/components/dialog/src/DialogTrigger.tsx +++ b/packages/components/dialog/src/DialogTrigger.tsx @@ -1,7 +1,6 @@ import * as RadixDialog from '@radix-ui/react-dialog' -import { ElementRef, forwardRef, type ReactElement } from 'react' +import { type ReactElement, Ref } from 'react' -type TriggerElement = ElementRef export interface TriggerProps { /** * Children of the component. @@ -11,10 +10,9 @@ export interface TriggerProps { * Change the component to the HTML tag or custom component of the only child. */ asChild?: RadixDialog.DialogTriggerProps['asChild'] + ref?: Ref } -export const Trigger = forwardRef( - (props: TriggerProps, ref): ReactElement => -) +export const Trigger = (props: TriggerProps): ReactElement => Trigger.displayName = 'Dialog.Trigger' diff --git a/packages/components/divider/CHANGELOG.md b/packages/components/divider/CHANGELOG.md index 3c4ff3b93..358acea8a 100644 --- a/packages/components/divider/CHANGELOG.md +++ b/packages/components/divider/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +### Code Refactoring + +- fixing remaining TS errors ([918544c](https://github.com/adevinta/spark/commit/918544c278a370ec82384842cc8f60b59982eb9f)) + +### BREAKING CHANGES + +- forwardRef has been removed from all packages + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/divider diff --git a/packages/components/divider/package.json b/packages/components/divider/package.json index 31be2a13f..310a7a716 100644 --- a/packages/components/divider/package.json +++ b/packages/components/divider/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/divider", - "version": "7.3.7", + "version": "8.0.0", "description": "A separator between two elements, usually consisting of a horizontal line.", "publishConfig": { "access": "public" @@ -24,7 +24,7 @@ }, "dependencies": { "@radix-ui/react-separator": "1.1.0", - "@spark-ui/internal-utils": "^7.3.7" + "@spark-ui/internal-utils": "^8.0.0" }, "peerDependencies": { "react": "^19.0", diff --git a/packages/components/divider/src/Divider.tsx b/packages/components/divider/src/Divider.tsx index 51344012b..1d24a53c6 100644 --- a/packages/components/divider/src/Divider.tsx +++ b/packages/components/divider/src/Divider.tsx @@ -1,11 +1,11 @@ import { Root as Separator } from '@radix-ui/react-separator' import { cx } from 'class-variance-authority' -import { forwardRef, HTMLAttributes, PropsWithRef, ReactElement, ReactNode } from 'react' +import { HTMLAttributes, ReactElement, ReactNode, Ref } from 'react' import { dividerStyles, type DividerStylesProps } from './Divider.styles' export interface DividerProps - extends PropsWithRef>, + extends HTMLAttributes, Omit { /** * Change the component to the HTML tag or custom component of the only child. @@ -28,36 +28,35 @@ export interface DividerProps * Color scheme of the divider. */ intent?: 'outline' | 'current' + ref?: Ref } -export const Divider = forwardRef( - ( - { - asChild, - className, - isDecorative = false, - children, - orientation = 'horizontal', - alignment = 'center', - intent = 'outline', - ...props - }, - ref - ) => { - const isEmpty = asChild ? !(children?.props as { children: ReactNode })?.children : !children +export const Divider = ({ + asChild, + className, + isDecorative = false, + children, + orientation = 'horizontal', + alignment = 'center', + intent = 'outline', + ref, + ...props +}: DividerProps) => { + const isEmpty = asChild ? !(children?.props as { children: ReactNode })?.children : !children - return ( - - {children} - - ) - } -) + return ( + + {children} + + ) +} + +Divider.displayName = 'Divider' diff --git a/packages/components/divider/src/DividerContent.tsx b/packages/components/divider/src/DividerContent.tsx index d3c169aa6..4503859c1 100644 --- a/packages/components/divider/src/DividerContent.tsx +++ b/packages/components/divider/src/DividerContent.tsx @@ -1,21 +1,20 @@ -import { forwardRef, HTMLAttributes, PropsWithRef, ReactNode } from 'react' +import { HTMLAttributes, ReactNode, Ref } from 'react' -export interface DividerContentProps extends PropsWithRef> { +export interface DividerContentProps extends HTMLAttributes { /** * Change the component to the HTML tag or custom component of the only child. */ asChild?: boolean children?: ReactNode + ref?: Ref } -export const DividerContent = forwardRef( - ({ children, ...props }, ref) => { - return children ? ( - - {children} - - ) : null - } -) +export const DividerContent = ({ children, ref, ...props }: DividerContentProps) => { + return children ? ( + + {children} + + ) : null +} DividerContent.displayName = 'Divider.Content' diff --git a/packages/components/drawer/CHANGELOG.md b/packages/components/drawer/CHANGELOG.md index f2a7ae3a4..8d7e65fd3 100644 --- a/packages/components/drawer/CHANGELOG.md +++ b/packages/components/drawer/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.0.0](https://github.com/adevinta/spark/compare/v7.3.7...v8.0.0) (2025-01-13) + +**Note:** Version bump only for package @spark-ui/drawer + ## [7.3.7](https://github.com/adevinta/spark/compare/v7.3.6...v7.3.7) (2025-01-08) **Note:** Version bump only for package @spark-ui/drawer diff --git a/packages/components/drawer/package.json b/packages/components/drawer/package.json index f5c05fe1c..8c701623a 100644 --- a/packages/components/drawer/package.json +++ b/packages/components/drawer/package.json @@ -1,6 +1,6 @@ { "name": "@spark-ui/drawer", - "version": "7.3.7", + "version": "8.0.0", "description": "A panel that slides out from the edge of the screen. It can be useful when you need users to complete a task or view some details without leaving the current page.", "publishConfig": { "access": "public" @@ -45,9 +45,9 @@ "license": "MIT", "dependencies": { "@radix-ui/react-dialog": "1.1.2", - "@spark-ui/icon": "^7.3.7", - "@spark-ui/icon-button": "^7.3.7", - "@spark-ui/icons": "^7.3.7", + "@spark-ui/icon": "^8.0.0", + "@spark-ui/icon-button": "^8.0.0", + "@spark-ui/icons": "^8.0.0", "class-variance-authority": "0.7.0" } } diff --git a/packages/components/drawer/src/DrawerBody.tsx b/packages/components/drawer/src/DrawerBody.tsx index c5d78bebd..78490db64 100644 --- a/packages/components/drawer/src/DrawerBody.tsx +++ b/packages/components/drawer/src/DrawerBody.tsx @@ -1,18 +1,23 @@ -import { forwardRef, type ReactNode, type Ref } from 'react' +import { type ReactNode, Ref } from 'react' import { drawerBodyStyles, type DrawerBodyStylesProps } from './DrawerBody.styles' export interface DrawerBodyProps extends DrawerBodyStylesProps { children: ReactNode className?: string + ref?: Ref } -export const DrawerBody = forwardRef( - ({ children, inset = false, className, ...rest }: DrawerBodyProps, ref: Ref) => ( -
    - {children} -
    - ) +export const DrawerBody = ({ + children, + inset = false, + className, + ref, + ...rest +}: DrawerBodyProps) => ( +
    + {children} +
    ) DrawerBody.displayName = 'Drawer.Body' diff --git a/packages/components/drawer/src/DrawerClose.tsx b/packages/components/drawer/src/DrawerClose.tsx index 9624f38fb..ac3dfd19a 100644 --- a/packages/components/drawer/src/DrawerClose.tsx +++ b/packages/components/drawer/src/DrawerClose.tsx @@ -1,11 +1,10 @@ import * as RadixDrawer from '@radix-ui/react-dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -type CloseElement = ElementRef -export type DrawerCloseProps = RadixDrawer.DialogCloseProps +export type DrawerCloseProps = RadixDrawer.DialogCloseProps & { + ref?: Ref +} -export const DrawerClose = forwardRef((props, ref) => ( - -)) +export const DrawerClose = (props: DrawerCloseProps) => DrawerClose.displayName = 'Drawer.Close' diff --git a/packages/components/drawer/src/DrawerCloseButton.tsx b/packages/components/drawer/src/DrawerCloseButton.tsx index 0af2faa4e..1aee8ef3f 100644 --- a/packages/components/drawer/src/DrawerCloseButton.tsx +++ b/packages/components/drawer/src/DrawerCloseButton.tsx @@ -2,38 +2,32 @@ import { Icon } from '@spark-ui/icon' import { IconButton, type IconButtonProps } from '@spark-ui/icon-button' import { Close as CloseSVG } from '@spark-ui/icons/dist/icons/Close' import { cx } from 'class-variance-authority' -import { ElementRef, forwardRef } from 'react' import { DrawerClose, type DrawerCloseProps } from './DrawerClose' -type CloseButtonElement = ElementRef export type DrawerCloseButtonProps = DrawerCloseProps & Pick -export const DrawerCloseButton = forwardRef( - ( - { - 'aria-label': ariaLabel, - className, - size = 'md', - intent = 'neutral', - design = 'ghost', - children = , - ...rest - }, - ref - ) => ( - - - {children} - - - ) +export const DrawerCloseButton = ({ + 'aria-label': ariaLabel, + className, + size = 'md', + intent = 'neutral', + design = 'ghost', + children = , + ref, + ...rest +}: DrawerCloseButtonProps) => ( + + + {children} + + ) DrawerCloseButton.displayName = 'Drawer.CloseButton' diff --git a/packages/components/drawer/src/DrawerContent.tsx b/packages/components/drawer/src/DrawerContent.tsx index c6b47a2e4..8a0f632c3 100644 --- a/packages/components/drawer/src/DrawerContent.tsx +++ b/packages/components/drawer/src/DrawerContent.tsx @@ -1,41 +1,46 @@ import * as RadixDrawer from '@radix-ui/react-dialog' -import { forwardRef, type Ref } from 'react' +import { Ref } from 'react' import { drawerContentStyles, type DrawerContentStylesProps } from './DrawerContent.styles' -export type DrawerContentProps = RadixDrawer.DialogContentProps & DrawerContentStylesProps +export type DrawerContentProps = RadixDrawer.DialogContentProps & + DrawerContentStylesProps & { + ref?: Ref + } -export const DrawerContent = forwardRef( - ( - { className, size = 'md', side = 'right', onInteractOutside, ...rest }: DrawerContentProps, - ref: Ref - ) => ( - { - const isForegroundElement = (e.target as HTMLElement).closest('.z-toast, .z-popover') +export const DrawerContent = ({ + className, + size = 'md', + side = 'right', + onInteractOutside, + ref, + ...rest +}: DrawerContentProps) => ( + { + const isForegroundElement = (e.target as HTMLElement).closest('.z-toast, .z-popover') - /** - * The focus trap of the drawer applies `pointer-events-none` on the body of the page in the background, but - * some components with an higher z-index have `pointer-events-auto` applied on them to remain interactive and ignore the focust trap (ex: a Snackbar with actions). - * - * Clicking on the snackbar will be considered as an "outside click" and close the drawer. We want to prevent this. - */ - if (isForegroundElement) { - e.preventDefault() - } + /** + * The focus trap of the drawer applies `pointer-events-none` on the body of the page in the background, but + * some components with an higher z-index have `pointer-events-auto` applied on them to remain interactive and ignore the focust trap (ex: a Snackbar with actions). + * + * Clicking on the snackbar will be considered as an "outside click" and close the drawer. We want to prevent this. + */ + if (isForegroundElement) { + e.preventDefault() + } - onInteractOutside?.(e) - }} - {...rest} - /> - ) + onInteractOutside?.(e) + }} + {...rest} + /> ) DrawerContent.displayName = 'Drawer.Content' diff --git a/packages/components/drawer/src/DrawerDescription.tsx b/packages/components/drawer/src/DrawerDescription.tsx index 30afeeba9..3ac51eb20 100644 --- a/packages/components/drawer/src/DrawerDescription.tsx +++ b/packages/components/drawer/src/DrawerDescription.tsx @@ -1,11 +1,12 @@ import * as RadixDrawer from '@radix-ui/react-dialog' -import { ElementRef, forwardRef } from 'react' +import { Ref } from 'react' -export type DescriptionElement = ElementRef -export type DrawerDescriptionProps = RadixDrawer.DialogDescriptionProps +export type DrawerDescriptionProps = RadixDrawer.DialogDescriptionProps & { + ref?: Ref +} -export const DrawerDescription = forwardRef( - (props, ref) => +export const DrawerDescription = (props: DrawerDescriptionProps) => ( + ) DrawerDescription.displayName = 'Drawer.Description' diff --git a/packages/components/drawer/src/DrawerFooter.tsx b/packages/components/drawer/src/DrawerFooter.tsx index d42a00486..1d6dfd3fd 100644 --- a/packages/components/drawer/src/DrawerFooter.tsx +++ b/packages/components/drawer/src/DrawerFooter.tsx @@ -1,12 +1,12 @@ import { cx } from 'class-variance-authority' -import { ComponentPropsWithoutRef, forwardRef, type ReactElement, type Ref } from 'react' +import { ComponentPropsWithoutRef, type ReactElement, Ref } from 'react' -export type DrawerFooterProps = ComponentPropsWithoutRef<'footer'> +export type DrawerFooterProps = ComponentPropsWithoutRef<'footer'> & { + ref?: Ref +} -export const DrawerFooter = forwardRef( - ({ className, ...rest }: DrawerFooterProps, ref: Ref): ReactElement => ( -