Stefan Pejcic 1 year ago
parent
commit
8595a9f4e5
100 changed files with 10270 additions and 0 deletions
  1. 11 0
      packages/ably/.npmignore
  2. 93 0
      packages/ably/CHANGELOG.md
  3. 21 0
      packages/ably/LICENSE
  4. 74 0
      packages/ably/README.md
  5. 6 0
      packages/ably/jest.config.js
  6. 50 0
      packages/ably/package.json
  7. 57 0
      packages/ably/src/index.ts
  8. 21 0
      packages/ably/tsconfig.declarations.json
  9. 11 0
      packages/ably/tsconfig.json
  10. 24 0
      packages/ably/tsup.config.ts
  11. 11 0
      packages/airtable/.npmignore
  12. 357 0
      packages/airtable/CHANGELOG.md
  13. 21 0
      packages/airtable/LICENSE
  14. 70 0
      packages/airtable/README.md
  15. 7 0
      packages/airtable/jest.config.js
  16. 54 0
      packages/airtable/package.json
  17. 80 0
      packages/airtable/refine.config.js
  18. 161 0
      packages/airtable/src/dataProvider.ts
  19. 5 0
      packages/airtable/src/index.ts
  20. 12 0
      packages/airtable/src/utils/generateFilter.ts
  21. 17 0
      packages/airtable/src/utils/generateFilterFormula.ts
  22. 50 0
      packages/airtable/src/utils/generateLogicalFilterFormula.ts
  23. 8 0
      packages/airtable/src/utils/generateSort.ts
  24. 6 0
      packages/airtable/src/utils/index.ts
  25. 9 0
      packages/airtable/src/utils/isContainsOperator.ts
  26. 14 0
      packages/airtable/src/utils/isSimpleOperator.ts
  27. 48 0
      packages/airtable/test/create/index.mock.ts
  28. 26 0
      packages/airtable/test/create/index.spec.ts
  29. 14 0
      packages/airtable/test/custom/index.spec.ts
  30. 41 0
      packages/airtable/test/deleteMany/index.mock.ts
  31. 15 0
      packages/airtable/test/deleteMany/index.spec.ts
  32. 41 0
      packages/airtable/test/deleteOne/index.mock.ts
  33. 15 0
      packages/airtable/test/deleteOne/index.spec.ts
  34. 150 0
      packages/airtable/test/getList/index.mock.ts
  35. 444 0
      packages/airtable/test/getList/index.spec.ts
  36. 43 0
      packages/airtable/test/getMany/index.mock.ts
  37. 20 0
      packages/airtable/test/getMany/index.spec.ts
  38. 43 0
      packages/airtable/test/getOne/index.mock.ts
  39. 17 0
      packages/airtable/test/getOne/index.spec.ts
  40. 11 0
      packages/airtable/test/jest.setup.js
  41. 43 0
      packages/airtable/test/update/index.mock.ts
  42. 21 0
      packages/airtable/test/update/index.spec.ts
  43. 46 0
      packages/airtable/test/updateMany/index.mock.ts
  44. 22 0
      packages/airtable/test/updateMany/index.spec.ts
  45. 33 0
      packages/airtable/test/utils/generateFilter.spec.ts
  46. 44 0
      packages/airtable/test/utils/generateFilterFormula.spec.ts
  47. 58 0
      packages/airtable/test/utils/generateLogicalFilterFormula.spec.ts
  48. 22 0
      packages/airtable/test/utils/generateSort.spec.ts
  49. 31 0
      packages/airtable/test/utils/isContainsOperator.spec.ts
  50. 30 0
      packages/airtable/test/utils/isSimpleOperator.spec.ts
  51. 21 0
      packages/airtable/tsconfig.declarations.json
  52. 8 0
      packages/airtable/tsconfig.json
  53. 24 0
      packages/airtable/tsup.config.ts
  54. 11 0
      packages/antd/.npmignore
  55. 1 0
      packages/antd/.npmrc
  56. 3380 0
      packages/antd/CHANGELOG.md
  57. 71 0
      packages/antd/README.md
  58. 31 0
      packages/antd/jest.config.js
  59. 75 0
      packages/antd/package.json
  60. 629 0
      packages/antd/refine.config.js
  61. 254 0
      packages/antd/src/assets/styles/reset.css
  62. 7 0
      packages/antd/src/components/autoSaveIndicator/index.spec.tsx
  63. 86 0
      packages/antd/src/components/autoSaveIndicator/index.tsx
  64. 53 0
      packages/antd/src/components/breadcrumb/index.spec.tsx
  65. 87 0
      packages/antd/src/components/breadcrumb/index.tsx
  66. 7 0
      packages/antd/src/components/buttons/clone/index.spec.tsx
  67. 117 0
      packages/antd/src/components/buttons/clone/index.tsx
  68. 7 0
      packages/antd/src/components/buttons/create/index.spec.tsx
  69. 117 0
      packages/antd/src/components/buttons/create/index.tsx
  70. 6 0
      packages/antd/src/components/buttons/delete/index.spec.tsx
  71. 150 0
      packages/antd/src/components/buttons/delete/index.tsx
  72. 6 0
      packages/antd/src/components/buttons/edit/index.spec.tsx
  73. 118 0
      packages/antd/src/components/buttons/edit/index.tsx
  74. 6 0
      packages/antd/src/components/buttons/export/index.spec.tsx
  75. 36 0
      packages/antd/src/components/buttons/export/index.tsx
  76. 7 0
      packages/antd/src/components/buttons/import/index.spec.tsx
  77. 40 0
      packages/antd/src/components/buttons/import/index.tsx
  78. 11 0
      packages/antd/src/components/buttons/index.ts
  79. 6 0
      packages/antd/src/components/buttons/list/index.spec.tsx
  80. 136 0
      packages/antd/src/components/buttons/list/index.tsx
  81. 6 0
      packages/antd/src/components/buttons/refresh/index.spec.tsx
  82. 76 0
      packages/antd/src/components/buttons/refresh/index.tsx
  83. 6 0
      packages/antd/src/components/buttons/save/index.spec.tsx
  84. 36 0
      packages/antd/src/components/buttons/save/index.tsx
  85. 6 0
      packages/antd/src/components/buttons/show/index.spec.tsx
  86. 117 0
      packages/antd/src/components/buttons/show/index.tsx
  87. 44 0
      packages/antd/src/components/buttons/types.ts
  88. 45 0
      packages/antd/src/components/crud/create/index.spec.tsx
  89. 144 0
      packages/antd/src/components/crud/create/index.tsx
  90. 521 0
      packages/antd/src/components/crud/edit/index.spec.tsx
  91. 231 0
      packages/antd/src/components/crud/edit/index.tsx
  92. 6 0
      packages/antd/src/components/crud/index.ts
  93. 45 0
      packages/antd/src/components/crud/list/index.spec.tsx
  94. 115 0
      packages/antd/src/components/crud/list/index.tsx
  95. 459 0
      packages/antd/src/components/crud/show/index.spec.tsx
  96. 216 0
      packages/antd/src/components/crud/show/index.tsx
  97. 74 0
      packages/antd/src/components/crud/types.ts
  98. 54 0
      packages/antd/src/components/fields/boolean/index.spec.tsx
  99. 26 0
      packages/antd/src/components/fields/boolean/index.tsx
  100. 7 0
      packages/antd/src/components/fields/date/index.spec.tsx

+ 11 - 0
packages/ably/.npmignore

@@ -0,0 +1,11 @@
+node_modules
+.DS_Store
+test
+jest.config.js
+**/*.spec.ts
+**/*.spec.tsx
+**/*.test.ts
+**/*.test.tsx
+tsup.config.ts
+tsconfig.test.json
+tsconfig.declarations.json

+ 93 - 0
packages/ably/CHANGELOG.md

@@ -0,0 +1,93 @@
+# @refinedev/ably
+
+## 4.1.4
+
+### Patch Changes
+
+-   [#5425](https://github.com/refinedev/refine/pull/5425) [`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@refinedev/core` peer dependencies to latest (`^4.46.1`)
+
+## 4.1.3
+
+### Patch Changes
+
+-   [#5330](https://github.com/refinedev/refine/pull/5330) [`7c8827b43d`](https://github.com/refinedev/refine/commit/7c8827b43d9e378818be6ee23032925c97ce02d5) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: upgrade nock library version to ^13.4.0
+
+## 4.1.2
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 4.1.1
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 4.1.0
+
+### Minor Changes
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    **Moving to the `@refinedev` scope 🎉🎉**
+
+    Moved to the `@refinedev` scope and updated our packages to use the new scope. From now on, all packages will be published under the `@refinedev` scope with their new names.
+
+    Now, we're also removing the `refine` prefix from all packages. So, the `@pankod/refine-core` package is now `@refinedev/core`, `@pankod/refine-antd` is now `@refinedev/antd`, and so on.
+
+### Patch Changes
+
+## 3.31.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+## 3.30.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+## 3.29.0
+
+### Minor Changes
+
+-   Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+## 3.28.0
+
+### Minor Changes
+
+-   [#2440](https://github.com/refinedev/refine/pull/2440) [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af) Thanks [@aliemir](https://github.com/aliemir)! - Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+## 3.27.0
+
+### Minor Changes
+
+-   All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.26.0
+
+### Minor Changes
+
+-   [#2217](https://github.com/refinedev/refine/pull/2217) [`b4aae00f77`](https://github.com/refinedev/refine/commit/b4aae00f77a2476d847994db21298ae25e4cf6e5) Thanks [@omeraplak](https://github.com/omeraplak)! - All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.22.2
+
+### Patch Changes
+
+-   Updated dependencies [[`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc)]:
+    -   @pankod/refine-core@3.23.2

+ 21 - 0
packages/ably/LICENSE

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

+ 74 - 0
packages/ably/README.md

@@ -0,0 +1,74 @@
+<div align="center" style="margin: 30px;">
+    <a href="https://refine.dev">
+    <img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
+    </a>
+</div>
+
+<br/>
+
+<div align="center">
+    <a href="https://refine.dev">Home Page</a> |
+    <a href="https://discord.gg/refine">Discord</a> |
+    <a href="https://refine.dev/examples/">Examples</a> | 
+    <a href="https://refine.dev/blog/">Blog</a> | 
+    <a href="https://refine.dev/docs/">Documentation</a>
+
+<br/>   
+<br/>
+
+[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
+[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
+
+<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
+
+</div>
+
+<br/>
+
+<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
+
+<br/>
+
+It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
+
+</div>
+
+<br/>
+
+# Ably integration for refine
+
+[Ably](https://ably.com/) reliably distributes realtime data to your users using the publish/subscribe messaging pattern over WebSocket connections.
+
+[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
+
+refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
+
+## Installation & Usage
+
+```
+npm install @refinedev/ably
+```
+
+```tsx
+import { liveProvider, Ably } from "@refinedev/ably";
+
+export const ablyClient = new Ably.Realtime("YOUR_API_TOKEN");
+
+const App = () => {
+  return (
+    <Refine
+      liveProvider={liveProvider(ablyClient)}
+      /* ... */
+    >
+      {/* ... */}
+    </Refine>
+  );
+};
+```
+
+## Documentation
+
+- For more detailed information and usage, refer to the [refine live provider documentation](https://refine.dev/docs/api-references/providers/live-provider/).
+- Refer to refine & Ably tutorial on [official Ably docs](https://ably.com/tutorials/react-admin-panel-with-ably-and-refine).
+- [Refer to documentation for more info about refine](https://refine.dev/docs/).
+- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

+ 6 - 0
packages/ably/jest.config.js

@@ -0,0 +1,6 @@
+module.exports = {
+    preset: "ts-jest",
+    rootDir: "./",
+    displayName: "ably",
+    testEnvironment: "jsdom",
+};

+ 50 - 0
packages/ably/package.json

@@ -0,0 +1,50 @@
+{
+  "name": "@refinedev/ably",
+  "description": "refine ably live provider. refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
+  "version": "4.1.4",
+  "license": "MIT",
+  "main": "dist/index.js",
+  "typings": "dist/index.d.ts",
+  "private": false,
+  "files": [
+    "dist",
+    "src"
+  ],
+  "engines": {
+    "node": ">=10"
+  },
+  "scripts": {
+    "start": "tsup --watch --format esm,cjs,iife --legacy-output",
+    "build": "tsup --format esm,cjs,iife --minify --legacy-output",
+    "test": "jest --passWithNoTests --runInBand",
+    "prepare": "npm run build"
+  },
+  "author": "refine",
+  "module": "dist/esm/index.js",
+  "devDependencies": {
+    "@refinedev/core": "^4.46.1",
+    "@esbuild-plugins/node-resolve": "^0.1.4",
+    "@types/jest": "^29.2.4",
+    "jest": "^29.3.1",
+    "jest-environment-jsdom": "^29.3.1",
+    "nock": "^13.4.0",
+    "ts-jest": "^29.0.3",
+    "tslib": "^2.3.1",
+    "tsup": "^6.7.0"
+  },
+  "dependencies": {
+    "ably": "^1.2.15"
+  },
+  "peerDependencies": {
+    "@refinedev/core": "^4.46.1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/refinedev/refine.git",
+    "directory": "packages/ably"
+  },
+  "gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
+  "publishConfig": {
+    "access": "public"
+  }
+}

+ 57 - 0
packages/ably/src/index.ts

@@ -0,0 +1,57 @@
+import { LiveProvider, LiveEvent } from "@refinedev/core";
+import Ably from "ably/promises";
+import { Types } from "ably";
+interface MessageType extends Types.Message {
+    data: LiveEvent;
+}
+
+const liveProvider = (client: Ably.Realtime): LiveProvider => {
+    return {
+        subscribe: ({ channel, types, params, callback }) => {
+            const channelInstance = client.channels.get(channel);
+
+            const listener = function (message: MessageType) {
+                if (types.includes("*") || types.includes(message.data.type)) {
+                    if (
+                        message.data.type !== "created" &&
+                        params?.ids !== undefined &&
+                        message.data?.payload?.ids !== undefined
+                    ) {
+                        if (
+                            params.ids
+                                .map(String)
+                                .filter((value) =>
+                                    message.data.payload.ids
+                                        ?.map(String)
+                                        .includes(value),
+                                ).length > 0
+                        ) {
+                            callback(message.data as LiveEvent);
+                        }
+                    } else {
+                        callback(message.data);
+                    }
+                }
+            };
+            channelInstance.subscribe(listener);
+
+            return { channelInstance, listener };
+        },
+
+        unsubscribe: (payload: {
+            channelInstance: Types.RealtimeChannelPromise;
+            listener: () => void;
+        }) => {
+            const { channelInstance, listener } = payload;
+            channelInstance.unsubscribe(listener);
+        },
+
+        publish: (event: LiveEvent) => {
+            const channelInstance = client.channels.get(event.channel);
+
+            channelInstance.publish(event.type, event);
+        },
+    };
+};
+
+export { liveProvider, Ably };

+ 21 - 0
packages/ably/tsconfig.declarations.json

@@ -0,0 +1,21 @@
+{
+    "extends": "./tsconfig.json",
+    "exclude": [
+        "node_modules",
+        "dist",
+        "test",
+        "../test/**/*",
+        "**/*.spec.ts",
+        "**/*.test.ts",
+        "**/*.spec.tsx",
+        "**/*.test.tsx"
+    ],
+    "compilerOptions": {
+        "outDir": "dist",
+        "declarationDir": "dist",
+        "declaration": true,
+        "emitDeclarationOnly": true,
+        "noEmit": false,
+        "declarationMap": true
+    }
+}

+ 11 - 0
packages/ably/tsconfig.json

@@ -0,0 +1,11 @@
+{
+  "include": [
+      "src",
+      "types"
+  ],
+  "extends": "../../tsconfig.build.json",
+  "compilerOptions": {
+      "rootDir": "./src",
+      "baseUrl": ".",
+  }
+}

+ 24 - 0
packages/ably/tsup.config.ts

@@ -0,0 +1,24 @@
+import { defineConfig } from "tsup";
+import { NodeResolvePlugin } from "@esbuild-plugins/node-resolve";
+
+export default defineConfig({
+    entry: ["src/index.ts"],
+    splitting: false,
+    sourcemap: true,
+    clean: false,
+    platform: "browser",
+    esbuildPlugins: [
+        NodeResolvePlugin({
+            extensions: [".js", "ts", "tsx", "jsx"],
+            onResolved: (resolved) => {
+                if (resolved.includes("node_modules")) {
+                    return {
+                        external: true,
+                    };
+                }
+                return resolved;
+            },
+        }),
+    ],
+    onSuccess: "tsc --project tsconfig.declarations.json",
+});

+ 11 - 0
packages/airtable/.npmignore

@@ -0,0 +1,11 @@
+node_modules
+.DS_Store
+test
+jest.config.js
+**/*.spec.ts
+**/*.spec.tsx
+**/*.test.ts
+**/*.test.tsx
+tsup.config.ts
+tsconfig.test.json
+tsconfig.declarations.json

+ 357 - 0
packages/airtable/CHANGELOG.md

@@ -0,0 +1,357 @@
+# @refinedev/airtable
+
+## 4.4.6
+
+### Patch Changes
+
+-   [#5425](https://github.com/refinedev/refine/pull/5425) [`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@refinedev/core` peer dependencies to latest (`^4.46.1`)
+
+## 4.4.5
+
+### Patch Changes
+
+-   [#5330](https://github.com/refinedev/refine/pull/5330) [`7c8827b43d`](https://github.com/refinedev/refine/commit/7c8827b43d9e378818be6ee23032925c97ce02d5) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: upgrade nock library version to ^13.4.0
+
+## 4.4.4
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 4.4.3
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 4.4.2
+
+### Patch Changes
+
+-   [#4285](https://github.com/refinedev/refine/pull/4285) [`b5cd3328504`](https://github.com/refinedev/refine/commit/b5cd332850428383e8b43f997cbb0340ac7f0dc6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: A bug that prevented data providers from being swizzled.
+
+## 4.4.1
+
+### Patch Changes
+
+-   [#4285](https://github.com/refinedev/refine/pull/4285) [`b5cd3328504`](https://github.com/refinedev/refine/commit/b5cd332850428383e8b43f997cbb0340ac7f0dc6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: A bug that prevented data providers from being swizzled.
+
+## 4.4.0
+
+### Minor Changes
+
+-   [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
+
+## 4.3.0
+
+### Minor Changes
+
+-   [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
+
+## 4.2.0
+
+### Minor Changes
+
+-   [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
+
+## 4.1.0
+
+### Minor Changes
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+
+    -   `metaData` prop is now deprecated for all data provider methods. Use `meta` prop instead.
+
+        > For backward compatibility, we still support `metaData` prop with refine v4.
+
+        ```diff
+        create: async ({
+        -    metaData
+        +    meta
+        }) => {
+            ...
+        },
+        ```
+
+    -   `sort`, `hasPagination`, and `metaData` parameters of `getList` method are now deprecated. Use `sorters`, `pagination`, and `meta` parameters instead.
+
+        > For backward compatibility, we still support `sort`, `hasPagination` and `metaData` props with refine v4.
+
+        ```diff
+        getList: async ({
+        -    sort
+        +    sorters
+        -    hasPagination
+        +    pagination: { mode: "off" | "server | "client" }
+        -    metaData
+        +    meta
+        }) => {
+            ...
+        },
+        ```
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    **Moving to the `@refinedev` scope 🎉🎉**
+
+    Moved to the `@refinedev` scope and updated our packages to use the new scope. From now on, all packages will be published under the `@refinedev` scope with their new names.
+
+    Now, we're also removing the `refine` prefix from all packages. So, the `@pankod/refine-core` package is now `@refinedev/core`, `@pankod/refine-antd` is now `@refinedev/antd`, and so on.
+
+### Patch Changes
+
+## 3.35.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+## 3.34.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+## 3.33.0
+
+### Minor Changes
+
+-   Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
+
+    ```
+    {
+      operator: "or",
+      value: [
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "John Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 30,
+            },
+          ],
+        },
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "JR Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 1,
+            },
+          ],
+        },
+      ],
+    }
+    ```
+
+## 3.32.0
+
+### Minor Changes
+
+-   [#2751](https://github.com/refinedev/refine/pull/2751) [`addff64c77`](https://github.com/refinedev/refine/commit/addff64c777e4c9f044a1a109cb05453e6e9f762) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
+
+    ```
+    {
+      operator: "or",
+      value: [
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "John Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 30,
+            },
+          ],
+        },
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "JR Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 1,
+            },
+          ],
+        },
+      ],
+    }
+    ```
+
+## 3.31.0
+
+### Minor Changes
+
+-   Updated `dataProvider` types with `Required` utility to mark `getMany`, `createMany`, `updateMany` and `deleteMany` as implemented.
+
+## 3.30.0
+
+### Minor Changes
+
+-   [#2688](https://github.com/refinedev/refine/pull/2688) [`508045ac30`](https://github.com/refinedev/refine/commit/508045ac30cd3948f68497e13fdf04f7c72ce387) Thanks [@aliemir](https://github.com/aliemir)! - Updated `dataProvider` types with `Required` utility to mark `getMany`, `createMany`, `updateMany` and `deleteMany` as implemented.
+
+## 3.29.0
+
+### Minor Changes
+
+-   Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+## 3.28.0
+
+### Minor Changes
+
+-   [#2440](https://github.com/refinedev/refine/pull/2440) [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af) Thanks [@aliemir](https://github.com/aliemir)! - Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+## 3.27.0
+
+### Minor Changes
+
+-   All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.26.0
+
+### Minor Changes
+
+-   [#2217](https://github.com/refinedev/refine/pull/2217) [`b4aae00f77`](https://github.com/refinedev/refine/commit/b4aae00f77a2476d847994db21298ae25e4cf6e5) Thanks [@omeraplak](https://github.com/omeraplak)! - All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.25.6
+
+### Patch Changes
+
+-   Updated pagination parameters default values and added `hasPagination` property to `getList` method of the data providers.
+
+    **Implementation**
+
+    Updated the `getList` method accordingly to the changes in the `useTable` and `useList` of `@pankod/refine-core`. `hasPagination` is used to disable pagination (defaults to `true`)
+
+    **Use Cases**
+
+    For some resources, there might be no support for pagination or users might want to see all of the data without any pagination, prior to these changes this was not supported in **refine** data providers.
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.36.0
+
+## 3.25.5
+
+### Patch Changes
+
+-   [#2050](https://github.com/refinedev/refine/pull/2050) [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5) Thanks [@ozkalai](https://github.com/ozkalai)! - Updated pagination parameters default values and added `hasPagination` property to `getList` method of the data providers.
+
+    **Implementation**
+
+    Updated the `getList` method accordingly to the changes in the `useTable` and `useList` of `@pankod/refine-core`. `hasPagination` is used to disable pagination (defaults to `true`)
+
+    **Use Cases**
+
+    For some resources, there might be no support for pagination or users might want to see all of the data without any pagination, prior to these changes this was not supported in **refine** data providers.
+
+-   Updated dependencies [[`ecde34a9b3`](https://github.com/refinedev/refine/commit/ecde34a9b38ef5667fa863f9ebb9dcb1cfff1651), [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5)]:
+    -   @pankod/refine-core@3.35.0
+
+## 3.25.4
+
+### Patch Changes
+
+-   Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
+
+    ```
+    // old v0.21.4
+    axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
+
+    // new v0.26.1
+    axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
+    ```
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.29.0
+
+## 3.25.3
+
+### Patch Changes
+
+-   Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
+
+    ```
+    // old v0.21.4
+    axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
+
+    // new v0.26.1
+    axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
+    ```
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.28.0
+
+## 3.25.2
+
+### Patch Changes
+
+-   Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
+
+    ```
+    // old v0.21.4
+    axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
+
+    // new v0.26.1
+    axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
+    ```
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.27.0
+
+## 3.25.1
+
+### Patch Changes
+
+-   [#1899](https://github.com/refinedev/refine/pull/1899) [`fbfea418a0`](https://github.com/refinedev/refine/commit/fbfea418a024a527a2b432c634f46a96d4f70d88) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
+
+    ```
+    // old v0.21.4
+    axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
+
+    // new v0.26.1
+    axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
+    ```
+
+-   Updated dependencies [[`2ba2a96fd2`](https://github.com/refinedev/refine/commit/2ba2a96fd24aa733c355ac9ef4c99b7d48115746)]:
+    -   @pankod/refine-core@3.26.0
+
+## 3.22.2
+
+### Patch Changes
+
+-   Updated dependencies [[`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc)]:
+    -   @pankod/refine-core@3.23.2

+ 21 - 0
packages/airtable/LICENSE

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

+ 70 - 0
packages/airtable/README.md

@@ -0,0 +1,70 @@
+<div align="center" style="margin: 30px;">
+    <a href="https://refine.dev">
+    <img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
+    </a>
+</div>
+
+<br/>
+
+<div align="center">
+    <a href="https://refine.dev">Home Page</a> |
+    <a href="https://discord.gg/refine">Discord</a> |
+    <a href="https://refine.dev/examples/">Examples</a> |
+    <a href="https://refine.dev/blog/">Blog</a> |
+    <a href="https://refine.dev/docs/">Documentation</a>
+
+<br/>
+<br/>
+
+[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
+[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
+
+<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
+
+</div>
+
+<br/>
+
+<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
+
+<br/>
+
+It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
+
+</div>
+
+# Airtable integration for refine
+
+[Airtable](https://www.airtable.com/) is a cloud-based platform for creating and sharing relational databases.
+
+[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
+
+refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
+
+## Installation & Usage
+
+```
+npm install @refinedev/airtable
+```
+
+```tsx
+import dataProvider from "@refinedev/airtable";
+
+const App = () => {
+  return (
+    <Refine
+      dataProvider={dataProvider("API_KEY", "BASE_ID")}
+      /* ... */
+    >
+      {/* ... */}
+    </Refine>
+  );
+};
+```
+
+## Documentation
+
+- For more detailed information and usage, refer to the [refine data provider documentation](https://refine.dev/docs/core/providers/data-provider).
+- [Refer to refine Airtable example](https://refine.dev/docs/examples/data-provider/airtable/).
+- [Refer to documentation for more info about refine](https://refine.dev/docs/).
+- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

+ 7 - 0
packages/airtable/jest.config.js

@@ -0,0 +1,7 @@
+module.exports = {
+    preset: "ts-jest",
+    rootDir: "./",
+    displayName: "airtable",
+    setupFilesAfterEnv: ["<rootDir>/test/jest.setup.js"],
+    testEnvironment: "jsdom",
+};

+ 54 - 0
packages/airtable/package.json

@@ -0,0 +1,54 @@
+{
+  "name": "@refinedev/airtable",
+  "description": "refine Airtable data provider. refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
+  "version": "4.4.6",
+  "license": "MIT",
+  "main": "dist/index.js",
+  "typings": "dist/index.d.ts",
+  "private": false,
+  "files": [
+    "dist",
+    "src",
+    "./refine.config.js"
+  ],
+  "engines": {
+    "node": ">=10"
+  },
+  "scripts": {
+    "start": "tsup --watch --format esm,cjs,iife --legacy-output",
+    "build": "tsup --format esm,cjs,iife --minify --legacy-output",
+    "test": "jest --passWithNoTests --runInBand",
+    "prepare": "npm run build"
+  },
+  "author": "refine",
+  "module": "dist/esm/index.js",
+  "devDependencies": {
+    "@refinedev/core": "4.46.2",
+    "@esbuild-plugins/node-resolve": "^0.1.4",
+    "@types/jest": "^29.2.4",
+    "jest": "^29.3.1",
+    "jest-environment-jsdom": "^29.3.1",
+    "nock": "^13.4.0",
+    "ts-jest": "^29.0.3",
+    "tslib": "^2.3.1",
+    "tsup": "^6.7.0"
+  },
+  "dependencies": {
+    "@qualifyze/airtable-formulator": "^1.0.1",
+    "airtable": "^0.11.1",
+    "asyncairtable": "^2.1.0",
+    "query-string": "^7.1.1"
+  },
+  "peerDependencies": {
+    "@refinedev/core": "^4.46.1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/refinedev/refine.git",
+    "directory": "packages/airtable"
+  },
+  "gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
+  "publishConfig": {
+    "access": "public"
+  }
+}

+ 80 - 0
packages/airtable/refine.config.js

@@ -0,0 +1,80 @@
+/** @type {import('@refinedev/cli').RefineConfig} */
+
+module.exports = {
+    group: "Data Provider",
+    swizzle: {
+        items: [
+            {
+                label: "Data Provider",
+                requiredPackages: [
+                    "@qualifyze/airtable-formulator@1.0.1",
+                    "airtable@0.11.1",
+                    "asyncairtable@2.1.0",
+                    "query-string@7.1.1",
+                ],
+                files: [
+                    {
+                        src: "./src/index.ts",
+                        dest: "./providers/airtable/index.ts",
+                    },
+                    {
+                        src: "./src/dataProvider.ts",
+                        dest: "./providers/airtable/dataProvider.ts",
+                    },
+                    {
+                        src: "./src/utils/index.ts",
+                        dest: "./providers/airtable/utils/index.ts",
+                    },
+                    {
+                        src: "./src/utils/generateFilter.ts",
+                        dest: "./providers/airtable/utils/generateFilter.ts",
+                    },
+                    {
+                        src: "./src/utils/generateFilterFormula.ts",
+                        dest: "./providers/airtable/utils/generateFilterFormula.ts",
+                    },
+                    {
+                        src: "./src/utils/generateLogicalFilterFormula.ts",
+                        dest: "./providers/airtable/utils/generateLogicalFilterFormula.ts",
+                    },
+                    {
+                        src: "./src/utils/generateLogicalFilterFormula.ts",
+                        dest: "./providers/airtable/utils/generateLogicalFilterFormula.ts",
+                    },
+                    {
+                        src: "./src/utils/generateSort.ts",
+                        dest: "./providers/airtable/utils/generateSort.ts",
+                    },
+                    {
+                        src: "./src/utils/isContainsOperator.ts",
+                        dest: "./providers/airtable/utils/isContainsOperator.ts",
+                    },
+                    {
+                        src: "./src/utils/isSimpleOperator.ts",
+                        dest: "./providers/airtable/utils/isSimpleOperator.ts",
+                    },
+                ],
+                message: `
+              **\`Usage\`**
+
+              \`\`\`
+              // title: App.tsx
+              import { dataProvider } from "./providers/airtable";
+
+              const API_TOKEN = "dummy-api-token";
+              const BASE_ID = "dummy-base-id";
+
+              const App = () => {
+                  return (
+                      <Refine
+                          dataProvider={dataProvider(API_TOKEN, BASE_ID)}
+                          /* ... */
+                      />
+                  );
+              }
+              \`\`\`
+              `,
+            },
+        ],
+    },
+};

+ 161 - 0
packages/airtable/src/dataProvider.ts

@@ -0,0 +1,161 @@
+import { DataProvider } from "@refinedev/core";
+import Airtable from "airtable";
+import { AirtableBase } from "airtable/lib/airtable_base";
+import { generateSort, generateFilter } from "./utils";
+
+export const dataProvider = (
+    apiKey: string,
+    baseId: string,
+    airtableClient?: AirtableBase,
+): Required<DataProvider> => {
+    const base =
+        airtableClient || new Airtable({ apiKey: apiKey }).base(baseId);
+
+    return {
+        getList: async ({ resource, pagination, sorters, filters }) => {
+            const {
+                current = 1,
+                pageSize = 10,
+                mode = "server",
+            } = pagination ?? {};
+
+            const generatedSort = generateSort(sorters) || [];
+            const queryFilters = generateFilter(filters);
+
+            const { all } = base(resource).select({
+                pageSize: 100,
+                sort: generatedSort,
+                ...(queryFilters ? { filterByFormula: queryFilters } : {}),
+            });
+
+            const data = await all();
+            const isServerPaginationEnabled = mode === "server";
+
+            return {
+                data: data
+                    .slice(
+                        isServerPaginationEnabled
+                            ? (current - 1) * pageSize
+                            : undefined,
+                        isServerPaginationEnabled
+                            ? current * pageSize
+                            : undefined,
+                    )
+                    .map((p) => ({
+                        id: p.id,
+                        ...p.fields,
+                    })) as any,
+                total: data.length,
+            };
+        },
+
+        getMany: async ({ resource, ids }) => {
+            const { all } = base(resource).select({
+                pageSize: 100,
+            });
+
+            const data = await all();
+
+            return {
+                data: data
+                    .filter((p) => ids.includes(p.id))
+                    .map((p) => ({
+                        id: p.id,
+                        ...p.fields,
+                    })) as any,
+            };
+        },
+
+        create: async ({ resource, variables }) => {
+            const { id, fields } = await base(resource).create(variables);
+
+            return {
+                data: {
+                    id: id,
+                    ...fields,
+                } as any,
+            };
+        },
+
+        createMany: async ({ resource, variables }) => {
+            const data = await base(resource).create(variables);
+
+            return {
+                data: data.map((p) => ({
+                    id: p.id,
+                    ...p.fields,
+                })) as any,
+            };
+        },
+
+        update: async ({ resource, id, variables }) => {
+            const { fields } = await base(resource).update(
+                id.toString(),
+                variables,
+            );
+
+            return {
+                data: {
+                    id,
+                    ...fields,
+                } as any,
+            };
+        },
+
+        updateMany: async ({ resource, ids, variables }) => {
+            const requestParams = ids.map((id) => ({
+                id: id.toString(),
+                fields: { ...variables },
+            }));
+            const data = await base(resource).update(requestParams);
+
+            return {
+                data: data.map((p) => ({
+                    id: p.id,
+                    ...p.fields,
+                })) as any,
+            };
+        },
+
+        getOne: async ({ resource, id }) => {
+            const { fields } = await base(resource).find(id.toString());
+
+            return {
+                data: {
+                    id,
+                    ...fields,
+                } as any,
+            };
+        },
+
+        deleteOne: async ({ resource, id }) => {
+            const { fields } = await base(resource).destroy(id.toString());
+
+            return {
+                data: {
+                    id,
+                    ...fields,
+                } as any,
+            };
+        },
+
+        deleteMany: async ({ resource, ids }) => {
+            const data = await base(resource).destroy(ids.map(String));
+
+            return {
+                data: data.map((p) => ({
+                    id: p.id,
+                    ...p.fields,
+                })) as any,
+            };
+        },
+
+        getApiUrl: () => {
+            throw Error("Not implemented on refine-airtable data provider.");
+        },
+
+        custom: async () => {
+            throw Error("Not implemented on refine-airtable data provider.");
+        },
+    };
+};

+ 5 - 0
packages/airtable/src/index.ts

@@ -0,0 +1,5 @@
+import { dataProvider } from "./dataProvider";
+
+export * from "./utils";
+export * from "./dataProvider";
+export default dataProvider;

+ 12 - 0
packages/airtable/src/utils/generateFilter.ts

@@ -0,0 +1,12 @@
+import { CrudFilters } from "@refinedev/core";
+import { compile } from "@qualifyze/airtable-formulator";
+import { generateFilterFormula } from "./generateFilterFormula";
+
+export const generateFilter = (filters?: CrudFilters): string | undefined => {
+    if (filters) {
+        // Top-level array has an implicit AND as per CRUDFilter design - https://refine.dev/docs/guides-and-concepts/data-provider/handling-filters/#logicalfilters
+        return compile(["AND", ...generateFilterFormula(filters)]);
+    }
+
+    return undefined;
+};

+ 17 - 0
packages/airtable/src/utils/generateFilterFormula.ts

@@ -0,0 +1,17 @@
+import { CrudFilters, LogicalFilter } from "@refinedev/core";
+import { Formula } from "@qualifyze/airtable-formulator";
+import { generateLogicalFilterFormula } from "./generateLogicalFilterFormula";
+
+export const generateFilterFormula = (filters: CrudFilters): Formula[] => {
+    const compound = filters.map((filter): Formula => {
+        const { operator, value } = filter;
+
+        if (operator === "or") {
+            return ["OR", ...generateFilterFormula(value)];
+        }
+
+        return generateLogicalFilterFormula(filter as LogicalFilter);
+    });
+
+    return compound;
+};

+ 50 - 0
packages/airtable/src/utils/generateLogicalFilterFormula.ts

@@ -0,0 +1,50 @@
+import { LogicalFilter } from "@refinedev/core";
+import { isContainsOperator, isContainssOperator } from "./isContainsOperator";
+import { isSimpleOperator, simpleOperatorMapping } from "./isSimpleOperator";
+import { Formula } from "@qualifyze/airtable-formulator";
+
+export const generateLogicalFilterFormula = (
+    filter: LogicalFilter,
+): Formula => {
+    const { field, operator, value } = filter;
+
+    if (isSimpleOperator(operator)) {
+        return [simpleOperatorMapping[operator], { field }, value];
+    }
+
+    if (isContainssOperator(operator)) {
+        const mappedOperator = {
+            containss: "!=",
+            ncontainss: "=",
+        } as const;
+
+        return [mappedOperator[operator], ["FIND", value, { field }], 0];
+    }
+
+    if (isContainsOperator(operator)) {
+        const mappedOperator = {
+            contains: "!=",
+            ncontains: "=",
+        } as const;
+
+        const find = [
+            "FIND",
+            ["LOWER", value],
+            ["LOWER", { field }],
+        ] as Formula;
+
+        return [mappedOperator[operator], find, 0];
+    }
+
+    if (operator === "null") {
+        return ["=", { field }, ["BLANK"]];
+    }
+
+    if (operator === "nnull") {
+        return ["!=", { field }, ["BLANK"]];
+    }
+
+    throw Error(
+        `Operator ${operator} is not supported for the Airtable data provider`,
+    );
+};

+ 8 - 0
packages/airtable/src/utils/generateSort.ts

@@ -0,0 +1,8 @@
+import { CrudSorting } from "@refinedev/core";
+
+export const generateSort = (sorters?: CrudSorting) => {
+    return sorters?.map((item) => ({
+        field: item.field,
+        direction: item.order,
+    }));
+};

+ 6 - 0
packages/airtable/src/utils/index.ts

@@ -0,0 +1,6 @@
+export * from "./isSimpleOperator";
+export * from "./isContainsOperator";
+export * from "./generateLogicalFilterFormula";
+export * from "./generateFilterFormula";
+export * from "./generateFilter";
+export * from "./generateSort";

+ 9 - 0
packages/airtable/src/utils/isContainsOperator.ts

@@ -0,0 +1,9 @@
+export const isContainssOperator = (
+    operator: any,
+): operator is "containss" | "ncontainss" =>
+    ["containss", "ncontainss"].includes(operator);
+
+export const isContainsOperator = (
+    operator: any,
+): operator is "contains" | "ncontains" =>
+    ["contains", "ncontains"].includes(operator);

+ 14 - 0
packages/airtable/src/utils/isSimpleOperator.ts

@@ -0,0 +1,14 @@
+export type SimpleOperators = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
+import { OperatorSymbol } from "@qualifyze/airtable-formulator";
+
+export const simpleOperatorMapping: Record<SimpleOperators, OperatorSymbol> = {
+    eq: "=",
+    ne: "!=",
+    lt: "<",
+    lte: "<=",
+    gt: ">",
+    gte: ">=",
+} as const;
+
+export const isSimpleOperator = (operator: any): operator is SimpleOperators =>
+    Object.keys(simpleOperatorMapping).includes(operator);

+ 48 - 0
packages/airtable/test/create/index.mock.ts

@@ -0,0 +1,48 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .post("/v0/appKYl1H4k9g73sBT/posts/", {
+        fields: {
+            title: "foo",
+            content: "bar",
+            status: "published",
+            category: ["recDBRJljBDFH4rIh"],
+        },
+    })
+    .query({})
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003158c3d0f82301400ffcb9bc5b4151d3aa2821227c3e4c750e8436a2a35e53118c27ff7b15eee6e02674143c4a63c16785126dbc622aff7b082d6a1b703e809c89147b6da10980f6468640edfb1f66ee8d0326c0ce12bc41fe8fb323b64d7d2bfb3437e4ae3b983270ba127ec89b3dac4470f33a3885cd9ca7d96b9124a266297a8b4921b2d85966a2d84b8c1fc0704ab8bf4a4000000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:10:12 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwhuRDEqN6Ub31j3; path=/; expires=Fri, 24 Jun 2022 13:10:12 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "160",
+            "Connection",
+            "Close",
+        ],
+    );

+ 26 - 0
packages/airtable/test/create/index.spec.ts

@@ -0,0 +1,26 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("create", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).create({
+            resource: "posts",
+            variables: {
+                title: "foo",
+                content: "bar",
+                status: "published",
+                category: ["recDBRJljBDFH4rIh"],
+            },
+        });
+
+        const { data } = response;
+
+        expect(data["title"]).toEqual("foo");
+        expect(data["status"]).toEqual("published");
+        expect(data["category"]).toEqual(["recDBRJljBDFH4rIh"]);
+        expect(data["content"]).toEqual("bar\n");
+    });
+});

+ 14 - 0
packages/airtable/test/custom/index.spec.ts

@@ -0,0 +1,14 @@
+import dataProvider from "../../src/index";
+
+describe("custom", () => {
+    it("correct get response", async () => {
+        try {
+            await dataProvider("keywoytODSr6xAqfg", "appKYl1H4k9g73sBT")
+                .custom!({ url: "users", method: "get" });
+        } catch (error) {
+            expect(error).toEqual(
+                Error("Not implemented on refine-airtable data provider."),
+            );
+        }
+    });
+});

+ 41 - 0
packages/airtable/test/deleteMany/index.mock.ts

@@ -0,0 +1,41 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .delete("/v0/appKYl1H4k9g73sBT/posts")
+    .query({ "records%5B%5D": "recdgFXue7JnGD90w" })
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003ab562a4a4dce2f4a2956b28aae564a49cd492d494d51b22a292a4dd551ca04b240f229e96e11a5a9e65e79ee2e9606e54ab5b1b5002d0259eb37000000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:17:00 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwTjdQAZbqbk0xGk; path=/; expires=Fri, 24 Jun 2022 13:17:00 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "71",
+            "Connection",
+            "Close",
+        ],
+    );

+ 15 - 0
packages/airtable/test/deleteMany/index.spec.ts

@@ -0,0 +1,15 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("deleteMany", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).deleteMany!({ resource: "posts", ids: ["recdgFXue7JnGD90w"] });
+
+        const { data } = response;
+
+        expect(data).not.toBeNull();
+    });
+});

+ 41 - 0
packages/airtable/test/deleteOne/index.mock.ts

@@ -0,0 +1,41 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .delete("/v0/appKYl1H4k9g73sBT/posts/recJEGeL2aB5rGFbC")
+    .query({})
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003ab564a49cd492d494d51b22a292a4dd551ca04b2948a5293bd5cdd537d8c129d4c8bdcdd929c956a016e8d991b29000000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:19:14 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwInLaPzl4WP7sXu; path=/; expires=Fri, 24 Jun 2022 13:19:13 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "59",
+            "Connection",
+            "Close",
+        ],
+    );

+ 15 - 0
packages/airtable/test/deleteOne/index.spec.ts

@@ -0,0 +1,15 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("deleteOne", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).deleteOne({ resource: "posts", id: "recJEGeL2aB5rGFbC" });
+
+        const { data } = response;
+
+        expect(data).not.toBeNull();
+    });
+});

+ 150 - 0
packages/airtable/test/getList/index.mock.ts

@@ -0,0 +1,150 @@
+import nock from "nock";
+import url from "url";
+
+const commonHeaders = [
+    "access-control-allow-headers",
+    "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+    "access-control-allow-methods",
+    "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+    "access-control-allow-origin",
+    "*",
+    "airtable-uncompressed-content-length",
+    "380",
+    "Content-Type",
+    "application/json; charset=utf-8",
+    "Date",
+    "Thu, 24 Jun 2021 12:24:32 GMT",
+    "Server",
+    "Tengine",
+    "Set-Cookie",
+    "brw=brwHislGvzT3Ws3Yf; path=/; expires=Fri, 24 Jun 2022 12:24:32 GMT; domain=.airtable.com; samesite=none; secure",
+    "Strict-Transport-Security",
+    "max-age=31536000; includeSubDomains; preload",
+    "Vary",
+    "Accept-Encoding",
+    "X-Content-Type-Options",
+    "nosniff",
+    "X-Frame-Options",
+    "DENY",
+    "Content-Length",
+    "233",
+    "Connection",
+    "Close",
+];
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .persist()
+    .get("/v0/appKYl1H4k9g73sBT/posts")
+    .query((query) => {
+        if (query.pageSize !== "100") return false;
+        if (query.filterByFormula === undefined) return false;
+
+        return true;
+    })
+    .reply(
+        200,
+        function () {
+            const parsed = new url.URL(this.req.path, "http://example.com");
+            const query = parsed.searchParams.get("filterByFormula");
+
+            return JSON.stringify({
+                offset: 0,
+                records: [
+                    {
+                        fields: {
+                            query,
+                        },
+                    },
+                ],
+            });
+        },
+        commonHeaders,
+    );
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .get("/v0/appKYl1H4k9g73sBT/posts")
+    .query({ pageSize: "100" })
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003954fc18ac23014fc157dc7a292562bdaa3c86a570f2215c5ad87da3cd7484cd634825aecb7fb82a0c74598c3639899375382c15c1b5e40f45382e01039a23fdaaea637dee517d58925346027503a4d09565889a41aa394bab6d446f25abb4e923cb3f8abcd95825cc47030ff9687c1f06bdc31f11e360d286c66cf94017fe7ad14c51eb9736965515962b38213525555cf8b5055a94a95e7bd88ccf3520577b219a4773c1147d7256081df64dda61f26be1f056114f65a8cb13529df9ba693b9d027b14bcc6c11dffedbf4d9228307cca9cf27d536f7073da8e6fb7c010000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "airtable-uncompressed-content-length",
+            "380",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 12:24:32 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwHislGvzT3Ws3Yf; path=/; expires=Fri, 24 Jun 2022 12:24:32 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "233",
+            "Connection",
+            "Close",
+        ],
+    );
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .get("/v0/appKYl1H4k9g73sBT/posts")
+    .query({
+        pageSize: "100",
+        "sort%5B0%5D%5Bfield%5D": "title",
+        "sort%5B0%5D%5Bdirection%5D": "desc",
+    })
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003958f416bc2401085ff8ace31a86ca211cd518235d64391144b1b0f4976ac2beb6ebbbb426b30bfdd490bf59243857718debc6f785381c1521b6e217aab4070881a63f5b816fa53ec52f3f49c9ca1073b81b2c954605dee4ef62776c0d221a76d993b7cd7e69b6e34743c5b2fe56116cf172393ec61db03279c44621628a5ee6cb491bc0b17020d12ca53716cb6010bfc3e1bf7fd30f5fd2808a37032608cbd52f2566dfa50bcacce7cccbfd42891edd53e4e851476ffbf6ea5560e95232cb79c94a9bafe9d48759da94c79de9f917b5ea6a0f5a3cef0ae9fb6972ba8a00e5b7c010000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "airtable-uncompressed-content-length",
+            "380",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:07:26 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brw0sykMWa9glzNWF; path=/; expires=Fri, 24 Jun 2022 13:07:25 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "237",
+            "Connection",
+            "Close",
+        ],
+    );

+ 444 - 0
packages/airtable/test/getList/index.spec.ts

@@ -0,0 +1,444 @@
+import { ConditionalFilter } from "@refinedev/core";
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("getList", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+        });
+
+        expect(response.data[0]["id"]).toBe("rec9GbXLzd6dxn4Il");
+        expect(response.data[0]["title"]).toBe("Hello World 3!");
+        expect(response.total).toBe(2);
+    });
+
+    it("correct sorting response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            sorters: [
+                {
+                    field: "title",
+                    order: "desc",
+                },
+            ],
+        });
+
+        expect(response.data[0]["id"]).toBe("recLKRioqifTrPUIz");
+        expect(response.data[0]["title"]).toBe("Hello World!");
+        expect(response.total).toBe(2);
+    });
+
+    it("correct equals filter for strings", async () => {
+        const filter = {
+            operator: "eq",
+            field: "title",
+            value: "Hello World!",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must equal exactly string
+        expect(response.data[0]["query"]).toBe('AND({title}="Hello World!")');
+    });
+
+    it("correct equals filter for numbers", async () => {
+        const filter = {
+            operator: "eq",
+            field: "age",
+            value: 100,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must equal exactly number
+        expect(response.data[0]["query"]).toBe("AND({age}=100)");
+    });
+
+    it("correct not equals filter for strings", async () => {
+        const filter = {
+            operator: "ne",
+            field: "title",
+            value: "Hello World!",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must not equal exactly string
+        expect(response.data[0]["query"]).toBe('AND({title}!="Hello World!")');
+    });
+
+    it("correct not equals filter for numbers", async () => {
+        const filter = {
+            operator: "ne",
+            field: "age",
+            value: 100,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must not equal exactly number
+        expect(response.data[0]["query"]).toBe("AND({age}!=100)");
+    });
+
+    it("correct less than filter", async () => {
+        const filter = {
+            operator: "lt",
+            field: "age",
+            value: 10,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must be less than value (as number)
+        expect(response.data[0]["query"]).toBe("AND({age}<10)");
+    });
+
+    it("correct less than or equal filter", async () => {
+        const filter = {
+            operator: "lte",
+            field: "age",
+            value: 10,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must be less than or equal value (as number)
+        expect(response.data[0]["query"]).toBe("AND({age}<=10)");
+    });
+
+    it("correct greater than filter", async () => {
+        const filter = {
+            operator: "gt",
+            field: "age",
+            value: 10,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must be greater than value (as number)
+        expect(response.data[0]["query"]).toBe("AND({age}>10)");
+    });
+
+    it("correct greater than or equal filter", async () => {
+        const filter = {
+            operator: "gte",
+            field: "age",
+            value: 10,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must be greater than or equal value (as number)
+        expect(response.data[0]["query"]).toBe("AND({age}>=10)");
+    });
+
+    it("correct contains filter", async () => {
+        const filter = {
+            operator: "containss",
+            field: "title",
+            value: "Hello",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // must find string in {field} - FIND returns non-zero value
+        expect(response.data[0]["query"]).toBe('AND(FIND("Hello",{title})!=0)');
+    });
+
+    it("correct not contains filter", async () => {
+        const filter = {
+            operator: "ncontainss",
+            field: "title",
+            value: "Hello",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // must not find string in {field} - FIND returns zero
+        expect(response.data[0]["query"]).toBe('AND(FIND("Hello",{title})=0)');
+    });
+
+    it("correct case-insensitive contains filter", async () => {
+        const filter = {
+            operator: "contains",
+            field: "title",
+            value: "Hello",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // must find lower-cased string in lower-cased {field} - lower-casing both values makes it case-insensitive
+        expect(response.data[0]["query"]).toBe(
+            'AND(FIND(LOWER("Hello"),LOWER({title}))!=0)',
+        );
+    });
+
+    it("correct case-insensitive not contains filter", async () => {
+        const filter = {
+            operator: "ncontains",
+            field: "title",
+            value: "Hello",
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // must not find lower-cased string in lower-cased {field} - lower-casing both values makes it case-insensitive
+        expect(response.data[0]["query"]).toBe(
+            'AND(FIND(LOWER("Hello"),LOWER({title}))=0)',
+        );
+    });
+
+    it("correct truthy null filter", async () => {
+        const filter = {
+            operator: "null",
+            field: "title",
+            value: undefined,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must be null (blank)
+        expect(response.data[0]["query"]).toBe("AND({title}=BLANK())");
+    });
+
+    it("correct falsy null filter", async () => {
+        const filter = {
+            operator: "nnull",
+            field: "title",
+            value: undefined,
+        } as const;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must not be null (blank)
+        expect(response.data[0]["query"]).toBe("AND({title}!=BLANK())");
+    });
+
+    it.each(["between", "nbetween"] as const)(
+        "fails for %s filter",
+        async (operator) => {
+            const filter = {
+                operator,
+                field: "age",
+                value: [10, 15],
+            } as const;
+
+            await expect(() => {
+                return dataProvider(
+                    "keywoytODSr6xAqfg",
+                    "appKYl1H4k9g73sBT",
+                ).getList({
+                    resource: "posts",
+                    filters: [filter],
+                });
+            }).rejects.toThrow(
+                `Operator ${operator} is not supported for the Airtable data provider`,
+            );
+        },
+    );
+
+    it.each(["in", "nin"] as const)("fails for %s filter", async (operator) => {
+        const filter = {
+            operator,
+            field: "posts",
+            value: ["uuid-1", "uuid-2"],
+        } as const;
+
+        await expect(() => {
+            return dataProvider(
+                "keywoytODSr6xAqfg",
+                "appKYl1H4k9g73sBT",
+            ).getList({
+                resource: "posts",
+                filters: [filter],
+            });
+        }).rejects.toThrow(
+            `Operator ${operator} is not supported for the Airtable data provider`,
+        );
+    });
+
+    it("correct 'or' conditional filter", async () => {
+        const filter = {
+            operator: "or",
+            value: [
+                {
+                    field: "title",
+                    operator: "eq",
+                    value: "Silver Bullet",
+                },
+                {
+                    field: "title",
+                    operator: "ne",
+                    value: "The Mythical Man Month",
+                },
+            ],
+        } as ConditionalFilter;
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: [filter],
+        });
+
+        expect(response.total).toBe(1);
+        // {field} must either be Silver Bullet or must not be Mythical Man Month
+        expect(response.data[0]["query"]).toBe(
+            'AND(OR({title}="Silver Bullet",{title}!="The Mythical Man Month"))',
+        );
+    });
+
+    it("correct compound 'or' conditional filter", async () => {
+        const filters = [
+            {
+                operator: "or",
+                value: [
+                    {
+                        field: "title",
+                        operator: "eq",
+                        value: "Silver Bullet",
+                    },
+                    {
+                        field: "title",
+                        operator: "ne",
+                        value: "The Mythical Man Month",
+                    },
+                ],
+            },
+            {
+                operator: "or",
+                value: [
+                    {
+                        field: "age",
+                        operator: "gt",
+                        value: 15,
+                    },
+                    {
+                        field: "age",
+                        operator: "lt",
+                        value: 25,
+                    },
+                ],
+            },
+        ] as ConditionalFilter[];
+
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getList({
+            resource: "posts",
+            filters: filters,
+        });
+
+        expect(response.total).toBe(1);
+        expect(response.data[0]["query"]).toBe(
+            'AND(OR({title}="Silver Bullet",{title}!="The Mythical Man Month"),OR({age}>15,{age}<25))',
+        );
+    });
+});

+ 43 - 0
packages/airtable/test/getMany/index.mock.ts

@@ -0,0 +1,43 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .get("/v0/appKYl1H4k9g73sBT/posts")
+    .query({ pageSize: "100" })
+    .reply(
+        200,
+        [
+            "1f8b080000000000000395905d6b83301486ff4a974b69875a959acb526aed1c88d875747a114d5c53b2a48be9585bf4b72f6eeca3e0608373111e5e4e9ef79c8124a590b806f0e10c2806b0039302c55e54851b278d571118828a12d665ce4051c5884e5542685e2ba40e9a83fda160b4de12ac6129b8225c695a2099f18e20451e853cea4fbaf577c151be24cbc05fdfeed51ce48d4e48a23338a54fdd72dbb4ad91e98d6c27b5c6d0f4a133b9364d73039ae1b7a41f14f7d1097bf8953b21bb90ecd7ba94984d9325db4d67f38523c32dc87f7aa31aebc978db7ebcf4b46dc6336e185f0019c67bb7cf832c086362b01692e1c1f80afcdac97253cb82b60bdd9e4ed14d42c533ad5219afc2537f274976a4547fabd423f72fb5bc7903b0079a9c21020000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "airtable-uncompressed-content-length",
+            "545",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:20:40 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwNd7NWRhWftbS0Q; path=/; expires=Fri, 24 Jun 2022 13:20:40 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "294",
+            "Connection",
+            "Close",
+        ],
+    );

+ 20 - 0
packages/airtable/test/getMany/index.spec.ts

@@ -0,0 +1,20 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("getMany", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getMany!({
+            resource: "posts",
+            ids: ["recLKRioqifTrPUIz", "rec9GbXLzd6dxn4Il"],
+        });
+
+        const { data } = response;
+
+        expect(data[0]["id"]).toBe("rec9GbXLzd6dxn4Il");
+        expect(data[1]["id"]).toBe("recLKRioqifTrPUIz");
+        expect(response.data.length).toBe(2);
+    });
+});

+ 43 - 0
packages/airtable/test/getOne/index.mock.ts

@@ -0,0 +1,43 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .get("/v0/appKYl1H4k9g73sBT/posts/recLKRioqifTrPUIz")
+    .query({})
+    .reply(
+        200,
+        [
+            "1f8b08000000000000031dcb410bc2201880e1bf52df790b958cf038c6d8aa430c23283a0cfd560e43523bd4d87fcf757edf6704a341804775d8b7c6bd4c2ffdf1d47c2183dea0d501c4082176f11dfedb802aa24e557511efce7f405c675d16edce0e4559d56bdf3ce0964134d16232355aeb1667e7ad5ec294a0c744b534cfb932c2684e3639e59252c1b8e0db1521e402d30fb10f929e9a000000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "airtable-uncompressed-content-length",
+            "154",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:21:53 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwQBAba4kMeu0MpF; path=/; expires=Fri, 24 Jun 2022 13:21:53 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "156",
+            "Connection",
+            "Close",
+        ],
+    );

+ 17 - 0
packages/airtable/test/getOne/index.spec.ts

@@ -0,0 +1,17 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("getOne", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).getOne({ resource: "posts", id: "recLKRioqifTrPUIz" });
+
+        const { data } = response;
+
+        expect(data.title).toBe("Hello World!");
+        expect(data.status).toBe("rejected");
+        expect(data.category).toEqual(["recDBRJljBDFH4rIh"]);
+    });
+});

+ 11 - 0
packages/airtable/test/jest.setup.js

@@ -0,0 +1,11 @@
+const fetch = require("node-fetch");
+const nock = require("nock");
+
+global.fetch = window.fetch = fetch;
+global.Request = window.Request = fetch.Request;
+global.Response = window.Response = fetch.Response;
+
+afterAll(() => {
+    nock.cleanAll();
+    nock.restore();
+});

+ 43 - 0
packages/airtable/test/update/index.mock.ts

@@ -0,0 +1,43 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .patch("/v0/appKYl1H4k9g73sBT/posts/recLKRioqifTrPUIz", {
+        fields: { title: "Hello World!!" },
+    })
+    .query({})
+    .reply(
+        200,
+        [
+            "1f8b08000000000000031dcb410bc2201880e1bfd2bef3162a19e1718cd8aa430c23283a0cfd560e43523bd4d87fcf757edf6704a341804775d8b7c6bd4c2ffdf1d47c2187dea0d501c4082176f11dfedb802aa24e557511efce7f405c675d95edce0e65b5ad57be79c02d8768a2c5646ab4d62dcece5b9d653025e931592dcd73ce8c305a907541b9a454302ef8664908b9c0f4030447c06c9b000000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:24:42 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwQrvJXnX0I6wkCt; path=/; expires=Fri, 24 Jun 2022 13:24:42 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "157",
+            "Connection",
+            "Close",
+        ],
+    );

+ 21 - 0
packages/airtable/test/update/index.spec.ts

@@ -0,0 +1,21 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("update", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).update({
+            resource: "posts",
+            id: "recLKRioqifTrPUIz",
+            variables: {
+                title: "Hello World!!",
+            },
+        });
+
+        const { data } = response;
+
+        expect(data["title"]).toBe("Hello World!!");
+    });
+});

+ 46 - 0
packages/airtable/test/updateMany/index.mock.ts

@@ -0,0 +1,46 @@
+import nock from "nock";
+
+nock("https://api.airtable.com:443", { encodedQueryParams: true })
+    .patch("/v0/appKYl1H4k9g73sBT/posts/", {
+        records: [
+            { id: "recLKRioqifTrPUIz", fields: { title: "Hello World!!!" } },
+            { id: "rec9GbXLzd6dxn4Il", fields: { title: "Hello World!!!" } },
+        ],
+    })
+    .query({})
+    .reply(
+        200,
+        [
+            "1f8b0800000000000003ad8f416bc2401085ff8a996350d9042336471135ad872229169b1c6276d49575577757680de6b73b69412f3d7810e630bcf7bee14d05064b6db885f8ab02c1216e84d9db5ce8a358a7e6fd2339431bd6026593a9c0bac29dec6f6c87a5434e6e5938dc68f343371a7a349cbfcadd70349ef64cb285bc0d4e3889c44c514add5a6823b9e7797021d420c13c15fbc60f59187458bf13446910c4611447832e636c49c97bb997c9ea7376e67dfead7a89fcbfdce1b492c26e1f6b576ae55039c20acb693255d77f1b4d5d672a53be7f130adfcf143ce3a7fc720554f78d147e010000",
+        ],
+        [
+            "access-control-allow-headers",
+            "authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
+            "access-control-allow-methods",
+            "DELETE,GET,OPTIONS,PATCH,POST,PUT",
+            "access-control-allow-origin",
+            "*",
+            "content-encoding",
+            "gzip",
+            "Content-Type",
+            "application/json; charset=utf-8",
+            "Date",
+            "Thu, 24 Jun 2021 13:26:53 GMT",
+            "Server",
+            "Tengine",
+            "Set-Cookie",
+            "brw=brwPAe5xxAm5wIYu2; path=/; expires=Fri, 24 Jun 2022 13:26:53 GMT; domain=.airtable.com; samesite=none; secure",
+            "Strict-Transport-Security",
+            "max-age=31536000; includeSubDomains; preload",
+            "Vary",
+            "Accept-Encoding",
+            "X-Content-Type-Options",
+            "nosniff",
+            "X-Frame-Options",
+            "DENY",
+            "Content-Length",
+            "235",
+            "Connection",
+            "Close",
+        ],
+    );

+ 22 - 0
packages/airtable/test/updateMany/index.spec.ts

@@ -0,0 +1,22 @@
+import dataProvider from "../../src/index";
+import "./index.mock";
+
+describe("updateMany", () => {
+    it("correct response", async () => {
+        const response = await dataProvider(
+            "keywoytODSr6xAqfg",
+            "appKYl1H4k9g73sBT",
+        ).updateMany!({
+            resource: "posts",
+            ids: ["recLKRioqifTrPUIz", "rec9GbXLzd6dxn4Il"],
+            variables: {
+                title: "Hello World!!!",
+            },
+        });
+
+        const { data } = response;
+
+        expect(data[0]["title"]).toBe("Hello World!!!");
+        expect(data[1]["title"]).toBe("Hello World!!!");
+    });
+});

+ 33 - 0
packages/airtable/test/utils/generateFilter.spec.ts

@@ -0,0 +1,33 @@
+import { CrudFilters } from "@refinedev/core";
+import { generateFilter } from "../../src/utils";
+
+describe("generateFilter", () => {
+    it("should return undefined when no filters are provided", () => {
+        expect(generateFilter()).toBeUndefined();
+    });
+
+    it("should return a filter formula when filters are provided", () => {
+        const filters: CrudFilters = [
+            { field: "name", operator: "eq", value: "John" },
+            { field: "age", operator: "gte", value: 30 },
+        ];
+        const expected = 'AND({name}="John",{age}>=30)';
+        expect(generateFilter(filters)).toBe(expected);
+    });
+
+    it("should return a complex filter formula with nested filters", () => {
+        const filters: CrudFilters = [
+            {
+                operator: "or",
+                value: [
+                    { field: "name", operator: "eq", value: "John" },
+                    { field: "name", operator: "eq", value: "Jane" },
+                ],
+            },
+            { field: "age", operator: "gte", value: 30 },
+        ];
+
+        const expected = 'AND(OR({name}="John",{name}="Jane"),{age}>=30)';
+        expect(generateFilter(filters)).toBe(expected);
+    });
+});

+ 44 - 0
packages/airtable/test/utils/generateFilterFormula.spec.ts

@@ -0,0 +1,44 @@
+import { CrudFilters } from "@refinedev/core";
+import { generateFilterFormula } from "../../src/utils";
+
+describe("generateFilterFormula", () => {
+    it("should return an empty array when no filters are provided", () => {
+        expect(generateFilterFormula([])).toEqual([]);
+    });
+
+    it("should return a formula array when filters are provided", () => {
+        const filters: CrudFilters = [
+            { field: "name", operator: "eq", value: "John" },
+            { field: "age", operator: "gte", value: 30 },
+        ];
+        const expected = [
+            ["=", { field: "name" }, "John"],
+            [">=", { field: "age" }, 30],
+        ];
+
+        expect(generateFilterFormula(filters)).toEqual(expected);
+    });
+
+    it("should return a complex formula array with nested filters", () => {
+        const filters: CrudFilters = [
+            {
+                operator: "or",
+                value: [
+                    { field: "name", operator: "eq", value: "John" },
+                    { field: "name", operator: "eq", value: "Jane" },
+                ],
+            },
+            { field: "age", operator: "gte", value: 30 },
+        ];
+        const expected = [
+            [
+                "OR",
+                ["=", { field: "name" }, "John"],
+                ["=", { field: "name" }, "Jane"],
+            ],
+            [">=", { field: "age" }, 30],
+        ];
+
+        expect(generateFilterFormula(filters)).toEqual(expected);
+    });
+});

+ 58 - 0
packages/airtable/test/utils/generateLogicalFilterFormula.spec.ts

@@ -0,0 +1,58 @@
+import { CrudFilter } from "@refinedev/core";
+
+import { generateLogicalFilterFormula } from "../../src/utils";
+import { LogicalFilter } from "@refinedev/core";
+
+describe("generateLogicalFilterFormula", () => {
+    it("should generate a formula for simple operators", () => {
+        const filter: CrudFilter = {
+            field: "age",
+            operator: "gte",
+            value: 30,
+        };
+        const expected = [">=", { field: "age" }, 30];
+
+        expect(generateLogicalFilterFormula(filter)).toEqual(expected);
+    });
+
+    it("should generate a formula for contains operators", () => {
+        const filter: CrudFilter = {
+            field: "name",
+            operator: "contains",
+            value: "John",
+        };
+        const expected = [
+            "!=",
+            ["FIND", ["LOWER", "John"], ["LOWER", { field: "name" }]],
+            0,
+        ];
+
+        expect(generateLogicalFilterFormula(filter)).toEqual(expected);
+    });
+
+    it("should generate a formula for null operators", () => {
+        const filter = { field: "email", operator: "null" } as LogicalFilter;
+        const expected = ["=", { field: "email" }, ["BLANK"]];
+
+        expect(generateLogicalFilterFormula(filter)).toEqual(expected);
+    });
+
+    it("should generate a formula for nnull operators", () => {
+        const filter = { field: "email", operator: "nnull" } as LogicalFilter;
+        const expected = ["!=", { field: "email" }, ["BLANK"]];
+
+        expect(generateLogicalFilterFormula(filter)).toEqual(expected);
+    });
+
+    it("should throw an error for unsupported operators", () => {
+        const filter = {
+            field: "age",
+            operator: "unsupported",
+            value: 30,
+        } as unknown as LogicalFilter;
+
+        expect(() => generateLogicalFilterFormula(filter)).toThrowError(
+            "Operator unsupported is not supported for the Airtable data provider",
+        );
+    });
+});

+ 22 - 0
packages/airtable/test/utils/generateSort.spec.ts

@@ -0,0 +1,22 @@
+import { CrudSorting } from "@refinedev/core";
+import { generateSort } from "../../src/utils";
+
+describe("generateSort", () => {
+    it("should return undefined if no sorters are provided", () => {
+        expect(generateSort(undefined)).toBeUndefined();
+    });
+
+    it("should generate an array of sorting objects", () => {
+        const sorters: CrudSorting = [
+            { field: "name", order: "asc" },
+            { field: "age", order: "desc" },
+        ];
+
+        const expected = [
+            { field: "name", direction: "asc" },
+            { field: "age", direction: "desc" },
+        ];
+
+        expect(generateSort(sorters)).toEqual(expected);
+    });
+});

+ 31 - 0
packages/airtable/test/utils/isContainsOperator.spec.ts

@@ -0,0 +1,31 @@
+import { isContainssOperator, isContainsOperator } from "../../src/utils";
+
+describe("Operators", () => {
+    describe("isContainssOperator", () => {
+        it("should return true if operator is containss", () => {
+            expect(isContainssOperator("containss")).toBe(true);
+        });
+
+        it("should return true if operator is ncontainss", () => {
+            expect(isContainssOperator("ncontainss")).toBe(true);
+        });
+
+        it("should return false if operator is not containss or ncontainss", () => {
+            expect(isContainssOperator("contains")).toBe(false);
+        });
+    });
+
+    describe("isContainsOperator", () => {
+        it("should return true if operator is contains", () => {
+            expect(isContainsOperator("contains")).toBe(true);
+        });
+
+        it("should return true if operator is ncontains", () => {
+            expect(isContainsOperator("ncontains")).toBe(true);
+        });
+
+        it("should return false if operator is not contains or ncontains", () => {
+            expect(isContainsOperator("containss")).toBe(false);
+        });
+    });
+});

+ 30 - 0
packages/airtable/test/utils/isSimpleOperator.spec.ts

@@ -0,0 +1,30 @@
+import { isSimpleOperator, simpleOperatorMapping } from "../../src/utils";
+
+describe("SimpleOperators", () => {
+    describe("isSimpleOperator", () => {
+        it("should return true if operator is a simple operator", () => {
+            expect(isSimpleOperator("eq")).toBe(true);
+            expect(isSimpleOperator("ne")).toBe(true);
+            expect(isSimpleOperator("lt")).toBe(true);
+            expect(isSimpleOperator("lte")).toBe(true);
+            expect(isSimpleOperator("gt")).toBe(true);
+            expect(isSimpleOperator("gte")).toBe(true);
+        });
+
+        it("should return false if operator is not a simple operator", () => {
+            expect(isSimpleOperator("contains")).toBe(false);
+            expect(isSimpleOperator("containss")).toBe(false);
+        });
+    });
+
+    describe("simpleOperatorMapping", () => {
+        it("should map simple operators to their corresponding Airtable symbols", () => {
+            expect(simpleOperatorMapping["eq"]).toBe("=");
+            expect(simpleOperatorMapping["ne"]).toBe("!=");
+            expect(simpleOperatorMapping["lt"]).toBe("<");
+            expect(simpleOperatorMapping["lte"]).toBe("<=");
+            expect(simpleOperatorMapping["gt"]).toBe(">");
+            expect(simpleOperatorMapping["gte"]).toBe(">=");
+        });
+    });
+});

+ 21 - 0
packages/airtable/tsconfig.declarations.json

@@ -0,0 +1,21 @@
+{
+    "extends": "./tsconfig.json",
+    "exclude": [
+        "node_modules",
+        "dist",
+        "test",
+        "../test/**/*",
+        "**/*.spec.ts",
+        "**/*.test.ts",
+        "**/*.spec.tsx",
+        "**/*.test.tsx"
+    ],
+    "compilerOptions": {
+        "outDir": "dist",
+        "declarationDir": "dist",
+        "declaration": true,
+        "emitDeclarationOnly": true,
+        "noEmit": false,
+        "declarationMap": true
+    }
+}

+ 8 - 0
packages/airtable/tsconfig.json

@@ -0,0 +1,8 @@
+{
+  "include": ["src", "types", "refine.config.js"],
+  "extends": "../../tsconfig.build.json",
+  "compilerOptions": {
+    "rootDir": "./src",
+    "baseUrl": "."
+  }
+}

+ 24 - 0
packages/airtable/tsup.config.ts

@@ -0,0 +1,24 @@
+import { defineConfig } from "tsup";
+import { NodeResolvePlugin } from "@esbuild-plugins/node-resolve";
+
+export default defineConfig({
+    entry: ["src/index.ts"],
+    splitting: false,
+    sourcemap: true,
+    clean: false,
+    platform: "browser",
+    esbuildPlugins: [
+        NodeResolvePlugin({
+            extensions: [".js", "ts", "tsx", "jsx"],
+            onResolved: (resolved) => {
+                if (resolved.includes("node_modules")) {
+                    return {
+                        external: true,
+                    };
+                }
+                return resolved;
+            },
+        }),
+    ],
+    onSuccess: "tsc --project tsconfig.declarations.json",
+});

+ 11 - 0
packages/antd/.npmignore

@@ -0,0 +1,11 @@
+node_modules
+.DS_Store
+test
+jest.config.js
+**/*.spec.ts
+**/*.spec.tsx
+**/*.test.ts
+**/*.test.tsx
+tsup.config.ts
+tsconfig.test.json
+tsconfig.declarations.json

+ 1 - 0
packages/antd/.npmrc

@@ -0,0 +1 @@
+legacy-peer-deps=true

+ 3380 - 0
packages/antd/CHANGELOG.md

@@ -0,0 +1,3380 @@
+# @refinedev/antd
+
+## 5.37.2
+
+### Patch Changes
+
+-   [#5465](https://github.com/refinedev/refine/pull/5465) [`00e00cbd98`](https://github.com/refinedev/refine/commit/00e00cbd98c34046ab83b299ede83401ae74fec1) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the type issue between `remark-gfm` and `react-markdown`. #5463
+
+## 5.37.1
+
+### Patch Changes
+
+-   [#5425](https://github.com/refinedev/refine/pull/5425) [`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@refinedev/core` peer dependencies to latest (`^4.46.1`)
+
+-   Updated dependencies [[`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5)]:
+    -   @refinedev/ui-types@1.22.4
+
+## 5.37.0
+
+### Minor Changes
+
+-   [#5307](https://github.com/refinedev/refine/pull/5307) [`f8e407f850`](https://github.com/refinedev/refine/commit/f8e407f85054bccf1e6ff45c84928bc01db7f5eb) Thanks [@jackprogramsjp](https://github.com/jackprogramsjp)! - feat: added `hideForm` props for `LoginPage` and `RegisterPage` for `AuthPage` feature.
+
+    Now with the `hideForm` props feature, you can be able to hide the forms (like email/password)
+    to only show the OAuth providers. This avoids having to make your own entire AuthPage.
+
+### Patch Changes
+
+-   [#5207](https://github.com/refinedev/refine/pull/5207) [`30a2834a81`](https://github.com/refinedev/refine/commit/30a2834a819ef857506b5c932500868e458fd319) Thanks [@mjomble](https://github.com/mjomble)! - chore: updated deprecated use of antd Progress
+
+-   [#5269](https://github.com/refinedev/refine/pull/5269) [`a23a0945d3`](https://github.com/refinedev/refine/commit/a23a0945d3fe003ae081fca1c47312dd6bf8c2ee) Thanks [@BatuhanW](https://github.com/BatuhanW)! - feat: add "autoComplete" field for Login pages.
+
+-   [#5325](https://github.com/refinedev/refine/pull/5325) [`7ff54b2060`](https://github.com/refinedev/refine/commit/7ff54b2060b0ce942c4170f744cbdf52d0940434) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fix: `<AuthPage />` styling issues on mobile screens.
+
+    chore: new tests are added to `<AuthPage />`.
+
+## 5.36.19
+
+### Patch Changes
+
+-   [#5259](https://github.com/refinedev/refine/pull/5259) [`eac3df87ffb`](https://github.com/refinedev/refine/commit/eac3df87ffbf61c913a6c8ea584e1d8c61e8d82e) Thanks [@aliemir](https://github.com/aliemir)! - Updated `<AutoSaveIndicator />` component to extend the `<AutoSaveIndicator />` from `@refinedev/core` with custom elements and render appropriate element based on the state.
+
+## 5.36.18
+
+### Patch Changes
+
+-   [#5199](https://github.com/refinedev/refine/pull/5199) [`2b8d658a17a`](https://github.com/refinedev/refine/commit/2b8d658a17a20ae347ba92b63487418f04ec255c) Thanks [@aliemir](https://github.com/aliemir)! - Now `useSelect`, `useRadioGroup` and `useCheckboxGroup` hooks accept 4th generic type `TOption` which allows you to change the type of options. By default `TOption` will be equal to `BaseOption` type which is `{ label: any; value: any; }`. If you want to change the type of options, you can do it like this:
+
+    ```tsx
+    import { useSelect } from "@refinedev/antd";
+    import { HttpError } from "@refinedev/core";
+
+    type MyData = {
+        id: number;
+        title: string;
+        description: string;
+        category: { id: string };
+    };
+
+    type Option = { label: MyData["title"]; value: MyData["id"] }; // equals to { label: string; value: number; }
+
+    useSelect<MyData, HttpError, MyData, Option>({
+        resource: "posts",
+    });
+    ```
+
+-   [#5199](https://github.com/refinedev/refine/pull/5199) [`2b8d658a17a`](https://github.com/refinedev/refine/commit/2b8d658a17a20ae347ba92b63487418f04ec255c) Thanks [@aliemir](https://github.com/aliemir)! - Updated return types of `useSelect`, `useRadioGroup` and `useCheckboxGroup` hooks to only include properties that actually being returned from the hook. Previously, the return types included all properties of the respective components, which was not correct.
+
+-   [#5201](https://github.com/refinedev/refine/pull/5201) [`760cfbaaa2a`](https://github.com/refinedev/refine/commit/760cfbaaa2ac8b8c070ade1e174784358cc112b0) Thanks [@aliemir](https://github.com/aliemir)! - Handle nested server side validation errors properly in `useForm`
+
+## 5.36.17
+
+### Patch Changes
+
+-   [#5199](https://github.com/refinedev/refine/pull/5199) [`2b8d658a17a`](https://github.com/refinedev/refine/commit/2b8d658a17a20ae347ba92b63487418f04ec255c) Thanks [@aliemir](https://github.com/aliemir)! - Now `useSelect`, `useRadioGroup` and `useCheckboxGroup` hooks accept 4th generic type `TOption` which allows you to change the type of options. By default `TOption` will be equal to `BaseOption` type which is `{ label: any; value: any; }`. If you want to change the type of options, you can do it like this:
+
+    ```tsx
+    import { useSelect } from "@refinedev/antd";
+    import { HttpError } from "@refinedev/core";
+
+    type MyData = {
+        id: number;
+        title: string;
+        description: string;
+        category: { id: string };
+    };
+
+    type Option = { label: MyData["title"]; value: MyData["id"] }; // equals to { label: string; value: number; }
+
+    useSelect<MyData, HttpError, MyData, Option>({
+        resource: "posts",
+    });
+    ```
+
+-   [#5199](https://github.com/refinedev/refine/pull/5199) [`2b8d658a17a`](https://github.com/refinedev/refine/commit/2b8d658a17a20ae347ba92b63487418f04ec255c) Thanks [@aliemir](https://github.com/aliemir)! - Updated return types of `useSelect`, `useRadioGroup` and `useCheckboxGroup` hooks to only include properties that actually being returned from the hook. Previously, the return types included all properties of the respective components, which was not correct.
+
+-   [#5201](https://github.com/refinedev/refine/pull/5201) [`760cfbaaa2a`](https://github.com/refinedev/refine/commit/760cfbaaa2ac8b8c070ade1e174784358cc112b0) Thanks [@aliemir](https://github.com/aliemir)! - Handle nested server side validation errors properly in `useForm`
+
+## 5.36.16
+
+### Patch Changes
+
+-   [#5189](https://github.com/refinedev/refine/pull/5189) [`34b5741289f`](https://github.com/refinedev/refine/commit/34b5741289fec9f1bf1e06b101d1c0965fc5c7e7) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: bump @ant-design/pro-layout dependency to `v7.17.12`.
+
+    Fixes https://github.com/refinedev/refine/issues/5172
+
+## 5.36.15
+
+### Patch Changes
+
+-   [#5189](https://github.com/refinedev/refine/pull/5189) [`34b5741289f`](https://github.com/refinedev/refine/commit/34b5741289fec9f1bf1e06b101d1c0965fc5c7e7) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: bump @ant-design/pro-layout dependency to `v7.17.12`.
+
+    Fixes https://github.com/refinedev/refine/issues/5172
+
+## 5.36.14
+
+### Patch Changes
+
+-   [#5134](https://github.com/refinedev/refine/pull/5134) [`e4769b23171`](https://github.com/refinedev/refine/commit/e4769b231716c63e5814718942025044e1a213c3) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: antd default `<ThemedSiderV2 />` is not collapsing.
+
+## 5.36.13
+
+### Patch Changes
+
+-   [#5134](https://github.com/refinedev/refine/pull/5134) [`e4769b23171`](https://github.com/refinedev/refine/commit/e4769b231716c63e5814718942025044e1a213c3) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: antd default `<ThemedSiderV2 />` is not collapsing.
+
+## 5.36.12
+
+### Patch Changes
+
+-   [#5114](https://github.com/refinedev/refine/pull/5114) [`00a9252c5de`](https://github.com/refinedev/refine/commit/00a9252c5de86aad544b0ca7d087c532c6d561fa) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: `<ThemedTitleV2 />` border-bottom removed.
+    fixed: `<ThemedLayoutV2 />` glitches on first render.
+
+## 5.36.11
+
+### Patch Changes
+
+-   [#5114](https://github.com/refinedev/refine/pull/5114) [`00a9252c5de`](https://github.com/refinedev/refine/commit/00a9252c5de86aad544b0ca7d087c532c6d561fa) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: `<ThemedTitleV2 />` border-bottom removed.
+    fixed: `<ThemedLayoutV2 />` glitches on first render.
+
+## 5.36.10
+
+### Patch Changes
+
+-   [#5098](https://github.com/refinedev/refine/pull/5098) [`672f7916af7`](https://github.com/refinedev/refine/commit/672f7916af74ed0d62eb806fde35fd7e56000b23) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fix: `undoableNotification` does not work when using `useNotificationProvider` due to a different `notification` instance.
+
+## 5.36.9
+
+### Patch Changes
+
+-   [#5098](https://github.com/refinedev/refine/pull/5098) [`672f7916af7`](https://github.com/refinedev/refine/commit/672f7916af74ed0d62eb806fde35fd7e56000b23) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fix: `undoableNotification` does not work when using `useNotificationProvider` due to a different `notification` instance.
+
+## 5.36.8
+
+### Patch Changes
+
+-   [#4945](https://github.com/refinedev/refine/pull/4945) [`b838412f0d0`](https://github.com/refinedev/refine/commit/b838412f0d0b790ba95f3c07a899a021d3cd2c84) Thanks [@MahirMahdi](https://github.com/MahirMahdi)! - fix: antd notificationProvider issue
+
+    Antd notification component could not access theme context, now it's fixed.
+
+    This release provides an alternative to exported `notificationProvider` value from type `NotificationProvider` to `() => NotificationProvider`. If you previously had customizations applied to the `notificationProvider` object, you may need to update your code like the following:
+
+    ```diff
+    - import { notificationProvider } from "@refinedev/antd";
+    + import { useNotificationProvider } from "@refinedev/antd";
+    + import { App as AntdApp } from "antd";
+
+    - const myNotificationProvider = {
+    -    ...notificationProvider,
+    -    open: (...args) => {
+    -        // do some operation here
+    -        notificationProvider.open(...args);
+    -    },
+    - }
+    + const myNotificationProvider = () => {
+    +     const notificationProvider = useNotificationProvider();
+    +     return {
+    +          ...notificationProvider,
+    +          open: (...args) => {
+    +             // do some operation here
+    +             notificationProvider.open(...args);
+    +          },
+    +     }
+    + }
+    }
+
+    const App = () => {
+        return (
+    +        <AntdApp>
+                <Refine
+                    /* ... */
+    +                notificationProvider={myNotificationProvider}
+                >
+                    /* ... */
+                </Refine>
+    +        </AntdApp>
+        );
+    }
+    ```
+
+## 5.36.7
+
+### Patch Changes
+
+-   [#4945](https://github.com/refinedev/refine/pull/4945) [`b838412f0d0`](https://github.com/refinedev/refine/commit/b838412f0d0b790ba95f3c07a899a021d3cd2c84) Thanks [@MahirMahdi](https://github.com/MahirMahdi)! - fix: antd notificationProvider issue
+
+    Antd notification component could not access theme context, now it's fixed.
+
+    This release provides an alternative to exported `notificationProvider` value from type `NotificationProvider` to `() => NotificationProvider`. If you previously had customizations applied to the `notificationProvider` object, you may need to update your code like the following:
+
+    ```diff
+    - import { notificationProvider } from "@refinedev/antd";
+    + import { useNotificationProvider } from "@refinedev/antd";
+    + import { App as AntdApp } from "antd";
+
+    - const myNotificationProvider = {
+    -    ...notificationProvider,
+    -    open: (...args) => {
+    -        // do some operation here
+    -        notificationProvider.open(...args);
+    -    },
+    - }
+    + const myNotificationProvider = () => {
+    +     const notificationProvider = useNotificationProvider();
+    +     return {
+    +          ...notificationProvider,
+    +          open: (...args) => {
+    +             // do some operation here
+    +             notificationProvider.open(...args);
+    +          },
+    +     }
+    + }
+    }
+
+    const App = () => {
+        return (
+    +        <AntdApp>
+                <Refine
+                    /* ... */
+    +                notificationProvider={myNotificationProvider}
+                >
+                    /* ... */
+                </Refine>
+    +        </AntdApp>
+        );
+    }
+    ```
+
+## 5.36.6
+
+### Patch Changes
+
+-   [#5026](https://github.com/refinedev/refine/pull/5026) [`a605e4cd318`](https://github.com/refinedev/refine/commit/a605e4cd318ed5542b46e9e11a86f2c75dbb694b) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: deprecated `<ThemedLayout />` and `<Layout />` components removed from `swizzle`.
+    From now on, users can swizzle `<ThemedLayoutV2 />` component instead.
+
+    feat: swizzled `<ThemedLayoutV2 />` component destination changed to `src/components/layout/` from `src/components/themedLayout`.
+
+## 5.36.5
+
+### Patch Changes
+
+-   [#5026](https://github.com/refinedev/refine/pull/5026) [`a605e4cd318`](https://github.com/refinedev/refine/commit/a605e4cd318ed5542b46e9e11a86f2c75dbb694b) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: deprecated `<ThemedLayout />` and `<Layout />` components removed from `swizzle`.
+    From now on, users can swizzle `<ThemedLayoutV2 />` component instead.
+
+    feat: swizzled `<ThemedLayoutV2 />` component destination changed to `src/components/layout/` from `src/components/themedLayout`.
+
+## 5.36.4
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 5.36.3
+
+### Patch Changes
+
+-   [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
+
+    -   fix grammar errors.
+    -   make all README.md files consistent.
+    -   add code example code snippets.
+
+## 5.36.2
+
+### Patch Changes
+
+-   [#4964](https://github.com/refinedev/refine/pull/4964) [`85b1ac0db5f`](https://github.com/refinedev/refine/commit/85b1ac0db5f8e61c7a78137aed0adf4bf2871848) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update @refinedev/core peer dependency versions.
+
+## 5.36.1
+
+### Patch Changes
+
+-   [#4964](https://github.com/refinedev/refine/pull/4964) [`85b1ac0db5f`](https://github.com/refinedev/refine/commit/85b1ac0db5f8e61c7a78137aed0adf4bf2871848) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update @refinedev/core peer dependency versions.
+
+## 5.36.0
+
+### Minor Changes
+
+-   [#4914](https://github.com/refinedev/refine/pull/4914) [`91a4d0da9f1`](https://github.com/refinedev/refine/commit/91a4d0da9f180ae358a448c7d187cee44f8c2299) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: [`optimisticUpdateMap`](https://refine.dev/docs/api-reference/core/hooks/data/useUpdate/#optimisticupdatemap) prop added to `useForm` hook. This prop allows you to update the data in the cache.
+
+    ```tsx
+    useForm({
+        mutationMode: "optimistic",
+        optimisticUpdateMap: {
+            list: true,
+            many: true,
+            detail: (previous, values, id) => {
+                if (!previous) {
+                    return null;
+                }
+
+                const data = {
+                    id,
+                    ...previous.data,
+                    ...values,
+                    foo: "bar",
+                };
+
+                return {
+                    ...previous,
+                    data,
+                };
+            },
+        },
+    });
+    ```
+
+### Patch Changes
+
+-   [#4903](https://github.com/refinedev/refine/pull/4903) [`e327cadc011`](https://github.com/refinedev/refine/commit/e327cadc011ce8696d7149252e1ad308005b1eff) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: when using [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/), `autoSave` parameters not passed to `@refinedev/core/useForm` hook.
+    From now on, you can use `autoSave` parameters in [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/) hook.
+
+    feat: add `invalidateOnUnmount` prop to [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/) hook.
+    feat: add `invalidateOnUnmount` and `invalidateOnClose` prop to [`useModalForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/) and [`useDrawerForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/) hooks.
+    From now on, you can use the use this props to invalidate queries upon unmount or close.
+
+## 5.35.0
+
+### Minor Changes
+
+-   [#4914](https://github.com/refinedev/refine/pull/4914) [`91a4d0da9f1`](https://github.com/refinedev/refine/commit/91a4d0da9f180ae358a448c7d187cee44f8c2299) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: [`optimisticUpdateMap`](https://refine.dev/docs/api-reference/core/hooks/data/useUpdate/#optimisticupdatemap) prop added to `useForm` hook. This prop allows you to update the data in the cache.
+
+    ```tsx
+    useForm({
+        mutationMode: "optimistic",
+        optimisticUpdateMap: {
+            list: true,
+            many: true,
+            detail: (previous, values, id) => {
+                if (!previous) {
+                    return null;
+                }
+
+                const data = {
+                    id,
+                    ...previous.data,
+                    ...values,
+                    foo: "bar",
+                };
+
+                return {
+                    ...previous,
+                    data,
+                };
+            },
+        },
+    });
+    ```
+
+### Patch Changes
+
+-   [#4903](https://github.com/refinedev/refine/pull/4903) [`e327cadc011`](https://github.com/refinedev/refine/commit/e327cadc011ce8696d7149252e1ad308005b1eff) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: when using [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/), `autoSave` parameters not passed to `@refinedev/core/useForm` hook.
+    From now on, you can use `autoSave` parameters in [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/) hook.
+
+    feat: add `invalidateOnUnmount` prop to [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/) hook.
+    feat: add `invalidateOnUnmount` and `invalidateOnClose` prop to [`useModalForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/) and [`useDrawerForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/) hooks.
+    From now on, you can use the use this props to invalidate queries upon unmount or close.
+
+## 5.34.2
+
+### Patch Changes
+
+-   [#4948](https://github.com/refinedev/refine/pull/4948) [`8e5efffbb23`](https://github.com/refinedev/refine/commit/8e5efffbb231bc3163c56f8e823ccb649755a9d4) Thanks [@aliemir](https://github.com/aliemir)! - Keep the hook and component names in builds for better debugging.
+
+## 5.34.1
+
+### Patch Changes
+
+-   [#4948](https://github.com/refinedev/refine/pull/4948) [`8e5efffbb23`](https://github.com/refinedev/refine/commit/8e5efffbb231bc3163c56f8e823ccb649755a9d4) Thanks [@aliemir](https://github.com/aliemir)! - Keep the hook and component names in builds for better debugging.
+
+## 5.34.0
+
+### Minor Changes
+
+-   [#4775](https://github.com/refinedev/refine/pull/4775) [`3052fb22449`](https://github.com/refinedev/refine/commit/3052fb22449c5e35c607e95c060c38ca48e00c82) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: `<RefreshButton />` does not refresh content #4618.
+    From now, `<RefreshButton />` uses `useInvalidate` hook to refresh data instead of `useOne`.
+
+### Patch Changes
+
+-   [#4772](https://github.com/refinedev/refine/pull/4772) [`c9cc4398e99`](https://github.com/refinedev/refine/commit/c9cc4398e9996a49f7ee9c4c5656661a66b591ad) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: antd `useModalForm` and `useDrawerForm` sends request twice when `syncWithLocation` is true
+
+-   [#4778](https://github.com/refinedev/refine/pull/4778) [`82909db10b4`](https://github.com/refinedev/refine/commit/82909db10b4ac1705e1354bff0c0d95951497725) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: fixed the `goToStep` of `useStepsForm` hook return type
+
+-   Updated dependencies [[`3052fb22449`](https://github.com/refinedev/refine/commit/3052fb22449c5e35c607e95c060c38ca48e00c82)]:
+    -   @refinedev/ui-types@1.22.0
+
+## 5.33.0
+
+### Minor Changes
+
+-   [#4775](https://github.com/refinedev/refine/pull/4775) [`3052fb22449`](https://github.com/refinedev/refine/commit/3052fb22449c5e35c607e95c060c38ca48e00c82) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: `<RefreshButton />` does not refresh content #4618.
+    From now, `<RefreshButton />` uses `useInvalidate` hook to refresh data instead of `useOne`.
+
+### Patch Changes
+
+-   [#4772](https://github.com/refinedev/refine/pull/4772) [`c9cc4398e99`](https://github.com/refinedev/refine/commit/c9cc4398e9996a49f7ee9c4c5656661a66b591ad) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: antd `useModalForm` and `useDrawerForm` sends request twice when `syncWithLocation` is true
+
+-   [#4778](https://github.com/refinedev/refine/pull/4778) [`82909db10b4`](https://github.com/refinedev/refine/commit/82909db10b4ac1705e1354bff0c0d95951497725) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: fixed the `goToStep` of `useStepsForm` hook return type
+
+-   Updated dependencies [[`3052fb22449`](https://github.com/refinedev/refine/commit/3052fb22449c5e35c607e95c060c38ca48e00c82)]:
+    -   @refinedev/ui-types@1.21.0
+
+## 5.32.0
+
+### Minor Changes
+
+-   [#4741](https://github.com/refinedev/refine/pull/4741) [`026ccf34356`](https://github.com/refinedev/refine/commit/026ccf34356bc621183894c0ee4518a6645369d1) Thanks [@aliemir](https://github.com/aliemir)! - Added `sideEffects` to `package.json` to help bundlers tree-shake unused code.
+
+### Patch Changes
+
+-   [#4741](https://github.com/refinedev/refine/pull/4741) [`026ccf34356`](https://github.com/refinedev/refine/commit/026ccf34356bc621183894c0ee4518a6645369d1) Thanks [@aliemir](https://github.com/aliemir)! - Updated `DateField` to set `dayjs` extension in component instead of a global side effect.
+
+## 5.31.0
+
+### Minor Changes
+
+-   [#4741](https://github.com/refinedev/refine/pull/4741) [`026ccf34356`](https://github.com/refinedev/refine/commit/026ccf34356bc621183894c0ee4518a6645369d1) Thanks [@aliemir](https://github.com/aliemir)! - Added `sideEffects` to `package.json` to help bundlers tree-shake unused code.
+
+### Patch Changes
+
+-   [#4741](https://github.com/refinedev/refine/pull/4741) [`026ccf34356`](https://github.com/refinedev/refine/commit/026ccf34356bc621183894c0ee4518a6645369d1) Thanks [@aliemir](https://github.com/aliemir)! - Updated `DateField` to set `dayjs` extension in component instead of a global side effect.
+
+## 5.30.0
+
+### Minor Changes
+
+-   [#4591](https://github.com/refinedev/refine/pull/4591) [`f8891ead2bd`](https://github.com/refinedev/refine/commit/f8891ead2bdb5f6743bbe9979230aa73ef3e69be) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: `autoSave` feature for [`Edit`](https://refine.dev/docs/api-reference/antd/components/basic-views/edit/#autosaveprops).
+    [useForm](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/#autosave), [useDrawerForm](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/#autosave), [useModalForm](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/#autosave), [useStepsForm](https://refine.dev/docs/api-reference/antd/hooks/form/useStepsForm/#autosave) hooks now accept `autoSave` object. `enabled` is a boolean value and `debounce` is a number value in milliseconds. `debounce` is optional and default value is `1000`.
+
+    ```
+    const { autoSaveProps } = useForm({
+        autoSave: {
+            enabled: true,
+            debounce: 2000, // not required, default is 1000
+        },
+    });
+
+    return (
+        <Edit
+            saveButtonProps={saveButtonProps}
+            // pass autoSaveProps to Edit component
+            autoSaveProps={autoSaveProps}
+        >
+            // form fields
+        </Edit>
+    );
+    ```
+
+    feat: Add [`<AutoSaveIndicator>`](https://refine.dev/docs/api-reference/antd/components/antd-auto-save-indicator/) component. It comes automatically when `autoSaveProps` is given to the `Edit` page. However, this component can be used to position it in a different place.
+
+    ```
+    import { AutoSaveIndicator } from "@refinedev/antd";
+    const { autoSaveProps } = useForm({
+        autoSave: {
+            enabled: true,
+            debounce: 2000, // not required, default is 1000
+        },
+    });
+
+    return (
+        <div>
+            <AutoSaveIndicator {...autoSaveProps}>
+        </div>
+    );
+    ```
+
+-   [#4652](https://github.com/refinedev/refine/pull/4652) [`96af6d25b7a`](https://github.com/refinedev/refine/commit/96af6d25b7a870a3c1c6fd33c30e0ca2224ed411) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: when the `dataProvider` returns rejected promise with `errors` field, `useForm` will automatically update the error state with the rejected `errors` field.
+
+    [Refer to the server-side form validation documentation for more information. →](https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/)
+
+### Patch Changes
+
+-   Updated dependencies [[`f8891ead2bd`](https://github.com/refinedev/refine/commit/f8891ead2bdb5f6743bbe9979230aa73ef3e69be)]:
+    -   @refinedev/ui-types@1.20.0
+
+## 5.29.0
+
+### Minor Changes
+
+-   [#4591](https://github.com/refinedev/refine/pull/4591) [`f8891ead2bd`](https://github.com/refinedev/refine/commit/f8891ead2bdb5f6743bbe9979230aa73ef3e69be) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: `autoSave` feature for [`Edit`](https://refine.dev/docs/api-reference/antd/components/basic-views/edit/#autosaveprops).
+    [useForm](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/#autosave), [useDrawerForm](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/#autosave), [useModalForm](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/#autosave), [useStepsForm](https://refine.dev/docs/api-reference/antd/hooks/form/useStepsForm/#autosave) hooks now accept `autoSave` object. `enabled` is a boolean value and `debounce` is a number value in milliseconds. `debounce` is optional and default value is `1000`.
+
+    ```
+    const { autoSaveProps } = useForm({
+        autoSave: {
+            enabled: true,
+            debounce: 2000, // not required, default is 1000
+        },
+    });
+
+    return (
+        <Edit
+            saveButtonProps={saveButtonProps}
+            // pass autoSaveProps to Edit component
+            autoSaveProps={autoSaveProps}
+        >
+            // form fields
+        </Edit>
+    );
+    ```
+
+    feat: Add [`<AutoSaveIndicator>`](https://refine.dev/docs/api-reference/antd/components/antd-auto-save-indicator/) component. It comes automatically when `autoSaveProps` is given to the `Edit` page. However, this component can be used to position it in a different place.
+
+    ```
+    import { AutoSaveIndicator } from "@refinedev/antd";
+    const { autoSaveProps } = useForm({
+        autoSave: {
+            enabled: true,
+            debounce: 2000, // not required, default is 1000
+        },
+    });
+
+    return (
+        <div>
+            <AutoSaveIndicator {...autoSaveProps}>
+        </div>
+    );
+    ```
+
+-   [#4652](https://github.com/refinedev/refine/pull/4652) [`96af6d25b7a`](https://github.com/refinedev/refine/commit/96af6d25b7a870a3c1c6fd33c30e0ca2224ed411) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: when the `dataProvider` returns rejected promise with `errors` field, `useForm` will automatically update the error state with the rejected `errors` field.
+
+    [Refer to the server-side form validation documentation for more information. →](https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/)
+
+### Patch Changes
+
+-   Updated dependencies [[`f8891ead2bd`](https://github.com/refinedev/refine/commit/f8891ead2bdb5f6743bbe9979230aa73ef3e69be)]:
+    -   @refinedev/ui-types@1.19.0
+
+## 5.28.0
+
+### Minor Changes
+
+-   [#4502](https://github.com/refinedev/refine/pull/4502) [`c7872ca621f`](https://github.com/refinedev/refine/commit/c7872ca621fdc6c0edd7ee113520bd898901ed38) Thanks [@Mr0nline](https://github.com/Mr0nline)! - feat: ability to tweak active sider items navigation
+
+    Visiting active sider items triggers page reloads due to them being links. We can now provide activeItemDisabled prop to disable such reloads.
+
+### Patch Changes
+
+-   [#4607](https://github.com/refinedev/refine/pull/4607) [`fed630dcc3e`](https://github.com/refinedev/refine/commit/fed630dcc3ef291efbfa96ed6f8e5c5448ac16a6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - test: added tests for `<ThemedSiderV2/>`.
+
+-   [#4609](https://github.com/refinedev/refine/pull/4609) [`48aaf739352`](https://github.com/refinedev/refine/commit/48aaf739352c6d8edc21cb111cc871de8f68549e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: `icon` and `label` alignment in `Breadcrumb` component
+
+    Fixed the issue that the `icon` and `label` to be misaligned in the `Breadcrumb` component.
+
+-   Updated dependencies [[`c7872ca621f`](https://github.com/refinedev/refine/commit/c7872ca621fdc6c0edd7ee113520bd898901ed38)]:
+    -   @refinedev/ui-types@1.18.0
+
+## 5.27.0
+
+### Minor Changes
+
+-   [#4502](https://github.com/refinedev/refine/pull/4502) [`c7872ca621f`](https://github.com/refinedev/refine/commit/c7872ca621fdc6c0edd7ee113520bd898901ed38) Thanks [@Mr0nline](https://github.com/Mr0nline)! - feat: ability to tweak active sider items navigation
+
+    Visiting active sider items triggers page reloads due to them being links. We can now provide activeItemDisabled prop to disable such reloads.
+
+### Patch Changes
+
+-   [#4607](https://github.com/refinedev/refine/pull/4607) [`fed630dcc3e`](https://github.com/refinedev/refine/commit/fed630dcc3ef291efbfa96ed6f8e5c5448ac16a6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - test: added tests for `<ThemedSiderV2/>`.
+
+-   [#4609](https://github.com/refinedev/refine/pull/4609) [`48aaf739352`](https://github.com/refinedev/refine/commit/48aaf739352c6d8edc21cb111cc871de8f68549e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: `icon` and `label` alignment in `Breadcrumb` component
+
+    Fixed the issue that the `icon` and `label` to be misaligned in the `Breadcrumb` component.
+
+-   Updated dependencies [[`c7872ca621f`](https://github.com/refinedev/refine/commit/c7872ca621fdc6c0edd7ee113520bd898901ed38)]:
+    -   @refinedev/ui-types@1.17.0
+
+## 5.26.0
+
+### Minor Changes
+
+-   [#4523](https://github.com/refinedev/refine/pull/4523) [`18d446b1069`](https://github.com/refinedev/refine/commit/18d446b1069c75b5033d0ce8defcb8c32fcce5cf) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: implement following hooks have `useLoadingOvertime` hook
+
+    -   [`useSelect`](https://refine.dev/docs/api-reference/antd/hooks/field/useSelect/#overtimeoptions)
+    -   [`useDrawerForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/#overtimeoptions)
+    -   [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/#overtimeoptions)
+    -   [`useModalForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/#overtimeoptions)
+    -   [`useStepsForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useStepsForm/#overtimeoptions)
+    -   [`useSimpleList`](https://refine.dev/docs/api-reference/antd/hooks/list/useSimpleList/#overtimeoptions)
+    -   [`useTable`](https://refine.dev/docs/api-reference/antd/hooks/table/useTable/#overtimeoptions)
+
+### Patch Changes
+
+-   [#4527](https://github.com/refinedev/refine/pull/4527) [`ceadcd29fc9`](https://github.com/refinedev/refine/commit/ceadcd29fc9e42c875a4b0a78622e9fc14b4ce42) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: prioritization of forgotten `identifier`
+
+    If `identifier` is provided, it will be used instead of `name`.
+
+    ```tsx
+    import { DeleteButton } from "@refinedev/antd";
+
+    <DeleteButton resource="identifier-value" recordItemId="123" />;
+    ```
+
+    fix: use translate keys with `identifier`
+
+    Previously, the translate keys were generated using resource `name`. This caused issues when you had multiple `resource` usage with the same name. Now the `translate` keys are generated using `identifier` if it's present.
+
+## 5.25.0
+
+### Minor Changes
+
+-   [#4523](https://github.com/refinedev/refine/pull/4523) [`18d446b1069`](https://github.com/refinedev/refine/commit/18d446b1069c75b5033d0ce8defcb8c32fcce5cf) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: implement following hooks have `useLoadingOvertime` hook
+
+    -   [`useSelect`](https://refine.dev/docs/api-reference/antd/hooks/field/useSelect/#overtimeoptions)
+    -   [`useDrawerForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useDrawerForm/#overtimeoptions)
+    -   [`useForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/#overtimeoptions)
+    -   [`useModalForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useModalForm/#overtimeoptions)
+    -   [`useStepsForm`](https://refine.dev/docs/api-reference/antd/hooks/form/useStepsForm/#overtimeoptions)
+    -   [`useSimpleList`](https://refine.dev/docs/api-reference/antd/hooks/list/useSimpleList/#overtimeoptions)
+    -   [`useTable`](https://refine.dev/docs/api-reference/antd/hooks/table/useTable/#overtimeoptions)
+
+### Patch Changes
+
+-   [#4527](https://github.com/refinedev/refine/pull/4527) [`ceadcd29fc9`](https://github.com/refinedev/refine/commit/ceadcd29fc9e42c875a4b0a78622e9fc14b4ce42) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: prioritization of forgotten `identifier`
+
+    If `identifier` is provided, it will be used instead of `name`.
+
+    ```tsx
+    import { DeleteButton } from "@refinedev/antd";
+
+    <DeleteButton resource="identifier-value" recordItemId="123" />;
+    ```
+
+    fix: use translate keys with `identifier`
+
+    Previously, the translate keys were generated using resource `name`. This caused issues when you had multiple `resource` usage with the same name. Now the `translate` keys are generated using `identifier` if it's present.
+
+## 5.24.0
+
+### Minor Changes
+
+-   [#4449](https://github.com/refinedev/refine/pull/4449) [`cc84d61bc5c`](https://github.com/refinedev/refine/commit/cc84d61bc5c8cfc8ac7da391f965471ecad6c445) Thanks [@BatuhanW](https://github.com/BatuhanW)! - feat: updated Create, List, Show, Edit, Delete, Clone buttons to respect new global `accessControlProvider` configuration.
+
+    fix: Delete button's text wasn't rendered as `reason` field of `accessControlProvider`.
+
+    Given the following `can` method:
+
+    ```ts
+    const accessControlProvider: IAccessControlContext = {
+        can: async (): Promise<CanReturnType> => {
+            return { can: false, reason: "Access Denied!" };
+        },
+    };
+    ```
+
+    If user is unauthorized, `Delete` button's text should be `Access Denied!` instead of default `Delete`.
+
+    This is the default behaviour for Create, List, Show, Edit, Delete, Clone buttons already.
+
+## 5.23.0
+
+### Minor Changes
+
+-   [#4449](https://github.com/refinedev/refine/pull/4449) [`cc84d61bc5c`](https://github.com/refinedev/refine/commit/cc84d61bc5c8cfc8ac7da391f965471ecad6c445) Thanks [@BatuhanW](https://github.com/BatuhanW)! - feat: updated Create, List, Show, Edit, Delete, Clone buttons to respect new global `accessControlProvider` configuration.
+
+    fix: Delete button's text wasn't rendered as `reason` field of `accessControlProvider`.
+
+    Given the following `can` method:
+
+    ```ts
+    const accessControlProvider: IAccessControlContext = {
+        can: async (): Promise<CanReturnType> => {
+            return { can: false, reason: "Access Denied!" };
+        },
+    };
+    ```
+
+    If user is unauthorized, `Delete` button's text should be `Access Denied!` instead of default `Delete`.
+
+    This is the default behaviour for Create, List, Show, Edit, Delete, Clone buttons already.
+
+## 5.22.0
+
+### Minor Changes
+
+-   [#4430](https://github.com/refinedev/refine/pull/4430) [`cf07d59587f`](https://github.com/refinedev/refine/commit/cf07d59587fae2adce97a79b40fdb60b9d9a9527) Thanks [@aliemir](https://github.com/aliemir)! - Updated the `useForm`, `useModalForm`, `useDrawerForm` and `useStepsForm` to accept `queryMeta` and `mutationMeta` properties of the `useForm` hook of `@refinedev/core`. These properties are used to pass specific meta values to the query or mutation. This is useful when you have overlapping values in your data provider's `getOne` and `update` methods. For example, you may want to change the `method` of the mutation to `PATCH` but if you pass it in the `meta` property, you'll end up changing the method of the `getOne` request as well.
+
+    `queryMeta` and `mutationMeta` has precedence over `meta`. This means that if you have the same property in `queryMeta` and `meta`, the value in `queryMeta` will be used.
+
+    **Usage**
+
+    ```tsx
+    import { useForm } from "@refinedev/core";
+
+    export const MyEditPage = () => {
+        const form = useForm({
+            // this is passed both to the mutation and the query requests
+            meta: {
+                myValue: "myValue",
+            },
+            // this is only passed to the query request
+            queryMeta: {
+                propertyOnlyWorksForQuery: "propertyOnlyWorksForQuery",
+            },
+            // this is only passed to the mutation request
+            mutationMeta: {
+                propertyOnlyWorksForMutation: "propertyOnlyWorksForMutation",
+            },
+        });
+    };
+    ```
+
+### Patch Changes
+
+-   [#4429](https://github.com/refinedev/refine/pull/4429) [`63daabcb703`](https://github.com/refinedev/refine/commit/63daabcb7037860bc36dff8cc417e9426e9ec027) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the issue of `formLoading` property in return values of `useStepsForm` hook which was not being toggled correctly when the form was submitted or the form data was being fetched.
+
+-   [#4431](https://github.com/refinedev/refine/pull/4431) [`c29a3618cf6`](https://github.com/refinedev/refine/commit/c29a3618cf6b577c36e90ec514f3a691c87aad8f) Thanks [@aliemir](https://github.com/aliemir)! - Updated the TSDoc comments to fix the broken links in the documentation.
+
+## 5.21.0
+
+### Minor Changes
+
+-   [#4430](https://github.com/refinedev/refine/pull/4430) [`cf07d59587f`](https://github.com/refinedev/refine/commit/cf07d59587fae2adce97a79b40fdb60b9d9a9527) Thanks [@aliemir](https://github.com/aliemir)! - Updated the `useForm`, `useModalForm`, `useDrawerForm` and `useStepsForm` to accept `queryMeta` and `mutationMeta` properties of the `useForm` hook of `@refinedev/core`. These properties are used to pass specific meta values to the query or mutation. This is useful when you have overlapping values in your data provider's `getOne` and `update` methods. For example, you may want to change the `method` of the mutation to `PATCH` but if you pass it in the `meta` property, you'll end up changing the method of the `getOne` request as well.
+
+    `queryMeta` and `mutationMeta` has precedence over `meta`. This means that if you have the same property in `queryMeta` and `meta`, the value in `queryMeta` will be used.
+
+    **Usage**
+
+    ```tsx
+    import { useForm } from "@refinedev/core";
+
+    export const MyEditPage = () => {
+        const form = useForm({
+            // this is passed both to the mutation and the query requests
+            meta: {
+                myValue: "myValue",
+            },
+            // this is only passed to the query request
+            queryMeta: {
+                propertyOnlyWorksForQuery: "propertyOnlyWorksForQuery",
+            },
+            // this is only passed to the mutation request
+            mutationMeta: {
+                propertyOnlyWorksForMutation: "propertyOnlyWorksForMutation",
+            },
+        });
+    };
+    ```
+
+### Patch Changes
+
+-   [#4429](https://github.com/refinedev/refine/pull/4429) [`63daabcb703`](https://github.com/refinedev/refine/commit/63daabcb7037860bc36dff8cc417e9426e9ec027) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the issue of `formLoading` property in return values of `useStepsForm` hook which was not being toggled correctly when the form was submitted or the form data was being fetched.
+
+-   [#4431](https://github.com/refinedev/refine/pull/4431) [`c29a3618cf6`](https://github.com/refinedev/refine/commit/c29a3618cf6b577c36e90ec514f3a691c87aad8f) Thanks [@aliemir](https://github.com/aliemir)! - Updated the TSDoc comments to fix the broken links in the documentation.
+
+## 5.20.0
+
+### Minor Changes
+
+-   [#4404](https://github.com/refinedev/refine/pull/4404) [`f67967e8c87`](https://github.com/refinedev/refine/commit/f67967e8c871b2252b4c1b827de3656bf153d1ee) Thanks [@salihozdemir](https://github.com/salihozdemir)! - refactor: fix name and state inconsistency in `<ThemedLayoutV2>`
+
+    `useSiderVisible` is deprecated, instead we created a new hook `useThemedLayoutContext` for it. `useThemedLayoutContext` similar to `useSiderVisible` but it returns more meaningful state names. However, `useSiderVisible` is still available for backward compatibility.
+
+    Updated `Sider` and `HamburgerMenu` components using `useThemedLayoutContext`.
+
+    ```tsx
+    import { useThemedLayoutContext } from "@refinedev/antd";
+
+    const {
+        siderCollapsed,
+        setSiderCollapsed,
+        mobileSiderOpen,
+        setMobileSiderOpen,
+    } = useThemedLayoutContext();
+    ```
+
+## 5.19.0
+
+### Minor Changes
+
+-   [#4404](https://github.com/refinedev/refine/pull/4404) [`f67967e8c87`](https://github.com/refinedev/refine/commit/f67967e8c871b2252b4c1b827de3656bf153d1ee) Thanks [@salihozdemir](https://github.com/salihozdemir)! - refactor: fix name and state inconsistency in `<ThemedLayoutV2>`
+
+    `useSiderVisible` is deprecated, instead we created a new hook `useThemedLayoutContext` for it. `useThemedLayoutContext` similar to `useSiderVisible` but it returns more meaningful state names. However, `useSiderVisible` is still available for backward compatibility.
+
+    Updated `Sider` and `HamburgerMenu` components using `useThemedLayoutContext`.
+
+    ```tsx
+    import { useThemedLayoutContext } from "@refinedev/antd";
+
+    const {
+        siderCollapsed,
+        setSiderCollapsed,
+        mobileSiderOpen,
+        setMobileSiderOpen,
+    } = useThemedLayoutContext();
+    ```
+
+## 5.18.2
+
+### Patch Changes
+
+-   [#4316](https://github.com/refinedev/refine/pull/4316) [`4690c627e05`](https://github.com/refinedev/refine/commit/4690c627e053a7e35eb8bcb1bfca808308bfa89d) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: fixed `className` for easier selection of all buttons and titles of CRUD components
+
+## 5.18.1
+
+### Patch Changes
+
+-   [#4316](https://github.com/refinedev/refine/pull/4316) [`4690c627e05`](https://github.com/refinedev/refine/commit/4690c627e053a7e35eb8bcb1bfca808308bfa89d) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: fixed `className` for easier selection of all buttons and titles of CRUD components
+
+## 5.18.0
+
+### Minor Changes
+
+-   [#4303](https://github.com/refinedev/refine/pull/4303) [`0c569f42b4e`](https://github.com/refinedev/refine/commit/0c569f42b4e7caec75928fd8a1ebeb337c95ff81) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added default button props into the renderer functions `headerButtons` and `footerButtons` in CRUD components.
+    Now, customization of the header and footer buttons can be achieved without losing the default functionality.
+
+    ```tsx
+    import {
+        DeleteButton,
+        EditButton,
+        ListButton,
+        RefreshButton,
+        Show,
+    } from "@refinedev/antd";
+
+    const PostShow = () => {
+        return (
+            <Show
+                headerButtons={({
+                    deleteButtonProps,
+                    editButtonProps,
+                    listButtonProps,
+                    refreshButtonProps,
+                }) => {
+                    return (
+                        <>
+                            {/* custom components */}
+                            {listButtonProps && (
+                                <ListButton
+                                    {...listButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            {editButtonProps && (
+                                <EditButton
+                                    {...editButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            {deleteButtonProps && (
+                                <DeleteButton
+                                    {...deleteButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            <RefreshButton
+                                {...refreshButtonProps}
+                                meta={{ foo: "bar" }}
+                            />
+                        </>
+                    );
+                }}
+            >
+                {/* ... */}
+            </Show>
+        );
+    };
+    ```
+
+-   [#4306](https://github.com/refinedev/refine/pull/4306) [`e6eb4dea627`](https://github.com/refinedev/refine/commit/e6eb4dea6279983d04a9f654ac2cd74915fba075) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: `syncWithLocation.syncId` default to `true` for `useDrawerForm` and `useModalForm`.
+
+### Patch Changes
+
+-   [#4312](https://github.com/refinedev/refine/pull/4312) [`9a5f79186c1`](https://github.com/refinedev/refine/commit/9a5f79186c107d52e12b8ff87558a3c3dd7807b8) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: added `className` for easier selection of all buttons and titles of CRUD components
+
+-   Updated dependencies [[`0c569f42b4e`](https://github.com/refinedev/refine/commit/0c569f42b4e7caec75928fd8a1ebeb337c95ff81), [`9a5f79186c1`](https://github.com/refinedev/refine/commit/9a5f79186c107d52e12b8ff87558a3c3dd7807b8)]:
+    -   @refinedev/ui-types@1.16.0
+
+## 5.17.0
+
+### Minor Changes
+
+-   [#4303](https://github.com/refinedev/refine/pull/4303) [`0c569f42b4e`](https://github.com/refinedev/refine/commit/0c569f42b4e7caec75928fd8a1ebeb337c95ff81) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added default button props into the renderer functions `headerButtons` and `footerButtons` in CRUD components.
+    Now, customization of the header and footer buttons can be achieved without losing the default functionality.
+
+    ```tsx
+    import {
+        DeleteButton,
+        EditButton,
+        ListButton,
+        RefreshButton,
+        Show,
+    } from "@refinedev/antd";
+
+    const PostShow = () => {
+        return (
+            <Show
+                headerButtons={({
+                    deleteButtonProps,
+                    editButtonProps,
+                    listButtonProps,
+                    refreshButtonProps,
+                }) => {
+                    return (
+                        <>
+                            {/* custom components */}
+                            {listButtonProps && (
+                                <ListButton
+                                    {...listButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            {editButtonProps && (
+                                <EditButton
+                                    {...editButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            {deleteButtonProps && (
+                                <DeleteButton
+                                    {...deleteButtonProps}
+                                    meta={{ foo: "bar" }}
+                                />
+                            )}
+                            <RefreshButton
+                                {...refreshButtonProps}
+                                meta={{ foo: "bar" }}
+                            />
+                        </>
+                    );
+                }}
+            >
+                {/* ... */}
+            </Show>
+        );
+    };
+    ```
+
+-   [#4306](https://github.com/refinedev/refine/pull/4306) [`e6eb4dea627`](https://github.com/refinedev/refine/commit/e6eb4dea6279983d04a9f654ac2cd74915fba075) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: `syncWithLocation.syncId` default to `true` for `useDrawerForm` and `useModalForm`.
+
+### Patch Changes
+
+-   [#4312](https://github.com/refinedev/refine/pull/4312) [`9a5f79186c1`](https://github.com/refinedev/refine/commit/9a5f79186c107d52e12b8ff87558a3c3dd7807b8) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: added `className` for easier selection of all buttons and titles of CRUD components
+
+-   Updated dependencies [[`0c569f42b4e`](https://github.com/refinedev/refine/commit/0c569f42b4e7caec75928fd8a1ebeb337c95ff81), [`9a5f79186c1`](https://github.com/refinedev/refine/commit/9a5f79186c107d52e12b8ff87558a3c3dd7807b8)]:
+    -   @refinedev/ui-types@1.15.0
+
+## 5.16.2
+
+### Patch Changes
+
+-   [#4295](https://github.com/refinedev/refine/pull/4295) [`7f24a6a2b14`](https://github.com/refinedev/refine/commit/7f24a6a2b14f1e10a2483298b13cc143861fb08f) Thanks [@salihozdemir](https://github.com/salihozdemir)! - chore: bump to latest version of `@refinedev/ui-types`
+
+-   Updated dependencies [[`dc62abc890f`](https://github.com/refinedev/refine/commit/dc62abc890f68be161c7035c28c0118216a9e0ec)]:
+    -   @refinedev/ui-types@1.14.0
+
+## 5.16.1
+
+### Patch Changes
+
+-   [#4295](https://github.com/refinedev/refine/pull/4295) [`7f24a6a2b14`](https://github.com/refinedev/refine/commit/7f24a6a2b14f1e10a2483298b13cc143861fb08f) Thanks [@salihozdemir](https://github.com/salihozdemir)! - chore: bump to latest version of `@refinedev/ui-types`
+
+## 5.16.0
+
+### Minor Changes
+
+-   [#4272](https://github.com/refinedev/refine/pull/4272) [`420d2442741`](https://github.com/refinedev/refine/commit/420d2442741d211561dd48c72bcb143ee5f44e9e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - feat: added the `fixed` prop to the `<ThemedSiderV2/>` to allow the sider to be fixed
+
+    The prop is optional and defaults to `false`. You can see the usage as follows:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedSiderV2 } from "@refinedev/antd";
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+             ...
+            >
+                <ThemedLayoutV2 Sider={() => <ThemedSiderV2 fixed />}>
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+-   [#4278](https://github.com/refinedev/refine/pull/4278) [`b14f2ad8a70`](https://github.com/refinedev/refine/commit/b14f2ad8a700d5ae157f437a8f610481d88ae09b) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added `autoSubmitClose` prop to `useEditableTable`.
+    Now you can choose whether to close the table's row after submitting the form or not.
+
+    ```tsx
+    const editableTable = useEditableTable({
+        autoSubmitClose: false,
+    });
+    ```
+
+### Patch Changes
+
+-   [#4267](https://github.com/refinedev/refine/pull/4267) [`5e128c76c16`](https://github.com/refinedev/refine/commit/5e128c76c162cb01822c283e567003a5b6ce62f8) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: `onFinish` prop override on `useDrawerForm` and `useModalForm` hook
+
+    When override `onFinish` prop using the `useDrawerForm` and `useModalForm` hooks, the modal not close after submit the form.
+
+-   [#4277](https://github.com/refinedev/refine/pull/4277) [`7172c1b42d2`](https://github.com/refinedev/refine/commit/7172c1b42d26ade22780527892ce26ceef15c838) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: renamed the `<ThemedHeaderV2/>` prop `isSticky` to `sticky`
+
+    To provide backwards compatibility, the old prop name is still supported, but it is deprecated and will be removed in the next major version.
+
+    Example:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedHeaderV2 } from "@refinedev/antd"; // or @refinedev/chakra-ui, @refinedev/mui, @refinedev/mantine
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+                ...
+            >
+                <ThemedLayoutV2
+                    Header={() => <ThemedHeaderV2 sticky />}
+                >
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+## 5.15.0
+
+### Minor Changes
+
+-   [#4272](https://github.com/refinedev/refine/pull/4272) [`420d2442741`](https://github.com/refinedev/refine/commit/420d2442741d211561dd48c72bcb143ee5f44e9e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - feat: added the `fixed` prop to the `<ThemedSiderV2/>` to allow the sider to be fixed
+
+    The prop is optional and defaults to `false`. You can see the usage as follows:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedSiderV2 } from "@refinedev/antd";
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+             ...
+            >
+                <ThemedLayoutV2 Sider={() => <ThemedSiderV2 fixed />}>
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+-   [#4278](https://github.com/refinedev/refine/pull/4278) [`b14f2ad8a70`](https://github.com/refinedev/refine/commit/b14f2ad8a700d5ae157f437a8f610481d88ae09b) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added `autoSubmitClose` prop to `useEditableTable`.
+    Now you can choose whether to close the table's row after submitting the form or not.
+
+    ```tsx
+    const editableTable = useEditableTable({
+        autoSubmitClose: false,
+    });
+    ```
+
+### Patch Changes
+
+-   [#4267](https://github.com/refinedev/refine/pull/4267) [`5e128c76c16`](https://github.com/refinedev/refine/commit/5e128c76c162cb01822c283e567003a5b6ce62f8) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: `onFinish` prop override on `useDrawerForm` and `useModalForm` hook
+
+    When override `onFinish` prop using the `useDrawerForm` and `useModalForm` hooks, the modal not close after submit the form.
+
+-   [#4277](https://github.com/refinedev/refine/pull/4277) [`7172c1b42d2`](https://github.com/refinedev/refine/commit/7172c1b42d26ade22780527892ce26ceef15c838) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: renamed the `<ThemedHeaderV2/>` prop `isSticky` to `sticky`
+
+    To provide backwards compatibility, the old prop name is still supported, but it is deprecated and will be removed in the next major version.
+
+    Example:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedHeaderV2 } from "@refinedev/antd"; // or @refinedev/chakra-ui, @refinedev/mui, @refinedev/mantine
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+                ...
+            >
+                <ThemedLayoutV2
+                    Header={() => <ThemedHeaderV2 sticky />}
+                >
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+## 5.14.0
+
+### Minor Changes
+
+-   [#4272](https://github.com/refinedev/refine/pull/4272) [`420d2442741`](https://github.com/refinedev/refine/commit/420d2442741d211561dd48c72bcb143ee5f44e9e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - feat: added the `fixed` prop to the `<ThemedSiderV2/>` to allow the sider to be fixed
+
+    The prop is optional and defaults to `false`. You can see the usage as follows:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedSiderV2 } from "@refinedev/antd";
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+             ...
+            >
+                <ThemedLayoutV2 Sider={() => <ThemedSiderV2 fixed />}>
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+-   [#4278](https://github.com/refinedev/refine/pull/4278) [`b14f2ad8a70`](https://github.com/refinedev/refine/commit/b14f2ad8a700d5ae157f437a8f610481d88ae09b) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added `autoSubmitClose` prop to `useEditableTable`.
+    Now you can choose whether to close the table's row after submitting the form or not.
+
+    ```tsx
+    const editableTable = useEditableTable({
+        autoSubmitClose: false,
+    });
+    ```
+
+### Patch Changes
+
+-   [#4267](https://github.com/refinedev/refine/pull/4267) [`5e128c76c16`](https://github.com/refinedev/refine/commit/5e128c76c162cb01822c283e567003a5b6ce62f8) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - fix: `onFinish` prop override on `useDrawerForm` and `useModalForm` hook
+
+    When override `onFinish` prop using the `useDrawerForm` and `useModalForm` hooks, the modal not close after submit the form.
+
+-   [#4277](https://github.com/refinedev/refine/pull/4277) [`7172c1b42d2`](https://github.com/refinedev/refine/commit/7172c1b42d26ade22780527892ce26ceef15c838) Thanks [@salihozdemir](https://github.com/salihozdemir)! - fix: renamed the `<ThemedHeaderV2/>` prop `isSticky` to `sticky`
+
+    To provide backwards compatibility, the old prop name is still supported, but it is deprecated and will be removed in the next major version.
+
+    Example:
+
+    ```tsx
+    import { Refine } from "@refinedev/core";
+    import { ThemedLayoutV2, ThemedHeaderV2 } from "@refinedev/antd"; // or @refinedev/chakra-ui, @refinedev/mui, @refinedev/mantine
+
+    const App: React.FC = () => {
+        return (
+            <Refine
+                ...
+            >
+                <ThemedLayoutV2
+                    Header={() => <ThemedHeaderV2 sticky />}
+                >
+                    {/* ... */}
+                </ThemedLayoutV2>
+            </Refine>
+        );
+    };
+    ```
+
+## 5.13.2
+
+### Patch Changes
+
+-   [#4241](https://github.com/refinedev/refine/pull/4241) [`fbe109b5a8b`](https://github.com/refinedev/refine/commit/fbe109b5a8ba8f5d870eab2d96b7477508bceec0) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added new generic types to the `useForm` hooks. Now you can pass the query types and the mutation types to the hook.
+
+## 5.13.1
+
+### Patch Changes
+
+-   [#4241](https://github.com/refinedev/refine/pull/4241) [`fbe109b5a8b`](https://github.com/refinedev/refine/commit/fbe109b5a8ba8f5d870eab2d96b7477508bceec0) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added new generic types to the `useForm` hooks. Now you can pass the query types and the mutation types to the hook.
+
+## 5.13.0
+
+### Minor Changes
+
+-   [#4209](https://github.com/refinedev/refine/pull/4209) [`3f4b5fef76f`](https://github.com/refinedev/refine/commit/3f4b5fef76f3558fc4466f455b9f55083cf47fc2) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: add `isSticky` prop to `ThemedHeaderV2` component
+
+    ```tsx
+    import { ThemedHeaderV2, ThemedLayoutV2 } from "@refinedev/antd";
+
+    const CustomHeader = () => <ThemedHeaderV2 isSticky={true} />;
+
+    const App = () => (
+        <Refine>
+            // ...
+            <ThemedLayoutV2 Header={CustomHeader}>
+                <Outlet />
+            </ThemedLayoutV2>
+            // ...
+        </Refine>
+    );
+    ```
+
+-   [#4232](https://github.com/refinedev/refine/pull/4232) [`c99bc0ad7f7`](https://github.com/refinedev/refine/commit/c99bc0ad7f7b71cf47e45a797acdea2325e6fbc8) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: `initialSiderCollapsed` added to `RefineThemedLayoutV2Props` to control initial state of `<ThemedSiderV2>`.
+    From now on, you can control the initial collapsed state of `<ThemedSiderV2>` by passing the `initialSiderCollapsed` prop to `<ThemedLayoutV2>`.
+
+    ```tsx
+    <ThemedLayoutV2
+        initialSiderCollapsed={true} // This will make the sider collapsed by default
+    >
+        {/* .. */}
+    </ThemedLayoutV2>
+    ```
+
+### Patch Changes
+
+-   Updated dependencies [[`c99bc0ad7f7`](https://github.com/refinedev/refine/commit/c99bc0ad7f7b71cf47e45a797acdea2325e6fbc8), [`3f4b5fef76f`](https://github.com/refinedev/refine/commit/3f4b5fef76f3558fc4466f455b9f55083cf47fc2)]:
+    -   @refinedev/ui-types@1.12.0
+
+## 5.12.0
+
+### Minor Changes
+
+-   [#4209](https://github.com/refinedev/refine/pull/4209) [`3f4b5fef76f`](https://github.com/refinedev/refine/commit/3f4b5fef76f3558fc4466f455b9f55083cf47fc2) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: add `isSticky` prop to `ThemedHeaderV2` component
+
+    ```tsx
+    import { ThemedHeaderV2, ThemedLayoutV2 } from "@refinedev/antd";
+
+    const CustomHeader = () => <ThemedHeaderV2 isSticky={true} />;
+
+    const App = () => (
+        <Refine>
+            // ...
+            <ThemedLayoutV2 Header={CustomHeader}>
+                <Outlet />
+            </ThemedLayoutV2>
+            // ...
+        </Refine>
+    );
+    ```
+
+-   [#4232](https://github.com/refinedev/refine/pull/4232) [`c99bc0ad7f7`](https://github.com/refinedev/refine/commit/c99bc0ad7f7b71cf47e45a797acdea2325e6fbc8) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: `initialSiderCollapsed` added to `RefineThemedLayoutV2Props` to control initial state of `<ThemedSiderV2>`.
+    From now on, you can control the initial collapsed state of `<ThemedSiderV2>` by passing the `initialSiderCollapsed` prop to `<ThemedLayoutV2>`.
+
+    ```tsx
+    <ThemedLayoutV2
+        initialSiderCollapsed={true} // This will make the sider collapsed by default
+    >
+        {/* .. */}
+    </ThemedLayoutV2>
+    ```
+
+### Patch Changes
+
+-   Updated dependencies [[`c99bc0ad7f7`](https://github.com/refinedev/refine/commit/c99bc0ad7f7b71cf47e45a797acdea2325e6fbc8), [`3f4b5fef76f`](https://github.com/refinedev/refine/commit/3f4b5fef76f3558fc4466f455b9f55083cf47fc2)]:
+    -   @refinedev/ui-types@1.11.0
+
+## 5.11.0
+
+### Minor Changes
+
+-   [#4194](https://github.com/refinedev/refine/pull/4194) [`8df15fe0e4e`](https://github.com/refinedev/refine/commit/8df15fe0e4e0fb2bb81102ed1e3a12a0a9532b80) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: `sorters.mode` prop added to `useTable` and `useDataGrid` hooks. This prop handles the sorting mode of the table. It can be either `server` or `off`.
+
+    -   **"off"**: `sorters` are not sent to the server. You can use the `sorters` value to sort the records on the client side.
+    -   **"server"**: Sorting is done on the server side. Records will be fetched by using the `sorters` value.
+
+    feat:`filters.mode` prop added to `useTable` and `useDataGrid` hooks. This prop handles the filtering mode of the table. It can be either `server` or `off`.
+
+    -   **"off"**: `filters` are not sent to the server. You can use the `filters` value to filter the records on the client side.
+    -   **"server"**: Filtering is done on the server side. Records will be fetched by using the `filters` value.
+
+## 5.10.0
+
+### Minor Changes
+
+-   [#4194](https://github.com/refinedev/refine/pull/4194) [`8df15fe0e4e`](https://github.com/refinedev/refine/commit/8df15fe0e4e0fb2bb81102ed1e3a12a0a9532b80) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: `sorters.mode` prop added to `useTable` and `useDataGrid` hooks. This prop handles the sorting mode of the table. It can be either `server` or `off`.
+
+    -   **"off"**: `sorters` are not sent to the server. You can use the `sorters` value to sort the records on the client side.
+    -   **"server"**: Sorting is done on the server side. Records will be fetched by using the `sorters` value.
+
+    feat:`filters.mode` prop added to `useTable` and `useDataGrid` hooks. This prop handles the filtering mode of the table. It can be either `server` or `off`.
+
+    -   **"off"**: `filters` are not sent to the server. You can use the `filters` value to filter the records on the client side.
+    -   **"server"**: Filtering is done on the server side. Records will be fetched by using the `filters` value.
+
+## 5.9.0
+
+### Minor Changes
+
+-   [#4193](https://github.com/refinedev/refine/pull/4193) [`3d28fccc1ca`](https://github.com/refinedev/refine/commit/3d28fccc1ca14cdf316d518935cb6c17500c62a4) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: add `ThemedLayoutV2` component and `useSiderVisible` hook
+
+    `ThemeLayout` is deprecated. Added `ThemedLayoutV2` instead. This update fixed some UI problems in the layout. Also, with the new `useSiderVisible` hook, it's easier to collapse/uncollapse the `Sider`.
+
+    See here for detailed [migration guideline](https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2).
+
+### Patch Changes
+
+-   Updated dependencies [[`deec38a034a`](https://github.com/refinedev/refine/commit/deec38a034a0b5ab2d7842e428f6fc3a1b8561fa)]:
+    -   @refinedev/ui-types@1.10.0
+
+## 5.8.0
+
+### Minor Changes
+
+-   [#4193](https://github.com/refinedev/refine/pull/4193) [`3d28fccc1ca`](https://github.com/refinedev/refine/commit/3d28fccc1ca14cdf316d518935cb6c17500c62a4) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: add `ThemedLayoutV2` component and `useSiderVisible` hook
+
+    `ThemeLayout` is deprecated. Added `ThemedLayoutV2` instead. This update fixed some UI problems in the layout. Also, with the new `useSiderVisible` hook, it's easier to collapse/uncollapse the `Sider`.
+
+    See here for detailed [migration guideline](https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2).
+
+### Patch Changes
+
+-   Updated dependencies [[`deec38a034a`](https://github.com/refinedev/refine/commit/deec38a034a0b5ab2d7842e428f6fc3a1b8561fa)]:
+    -   @refinedev/ui-types@1.9.0
+
+## 5.7.0
+
+### Minor Changes
+
+-   [#4193](https://github.com/refinedev/refine/pull/4193) [`3d28fccc1ca`](https://github.com/refinedev/refine/commit/3d28fccc1ca14cdf316d518935cb6c17500c62a4) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - feat: add `ThemedLayoutV2` component and `useSiderVisible` hook
+
+    `ThemeLayout` is deprecated. Added `ThemedLayoutV2` instead. This update fixed some UI problems in the layout. Also, with the new `useSiderVisible` hook, it's easier to collapse/uncollapse the `Sider`.
+
+    See here for detailed [migration guideline](https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2).
+
+### Patch Changes
+
+-   Updated dependencies [[`deec38a034a`](https://github.com/refinedev/refine/commit/deec38a034a0b5ab2d7842e428f6fc3a1b8561fa)]:
+    -   @refinedev/ui-types@1.8.0
+
+## 5.6.0
+
+### Minor Changes
+
+-   [#4113](https://github.com/refinedev/refine/pull/4113) [`1c13602e308`](https://github.com/refinedev/refine/commit/1c13602e308ffba93099922c144966f25fb2087d) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added missing third generic parameter to hooks which are using `useQuery` internally.
+
+    For example:
+
+    ```ts
+    import { useOne, HttpError } from "@refinedev/core";
+
+    const { data } = useOne<{ count: string }, HttpError, { count: number }>({
+        resource: "product-count",
+        queryOptions: {
+            select: (rawData) => {
+                return {
+                    data: {
+                        count: Number(rawData?.data?.count),
+                    },
+                };
+            },
+        },
+    });
+
+    console.log(typeof data?.data.count); // number
+    ```
+
+### Patch Changes
+
+-   [#4113](https://github.com/refinedev/refine/pull/4113) [`1c13602e308`](https://github.com/refinedev/refine/commit/1c13602e308ffba93099922c144966f25fb2087d) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Updated the generic type name of hooks that use `useQuery` to synchronize generic type names with `tanstack-query`.
+
+## 5.5.2
+
+### Patch Changes
+
+-   [#4120](https://github.com/refinedev/refine/pull/4120) [`1f310bd7b69`](https://github.com/refinedev/refine/commit/1f310bd7b6900f534bb57db90d3fc8a6ea4364c9) Thanks [@aliemir](https://github.com/aliemir)! - Fix broken `useModalForm` and `useDrawerForm` with `create` actions.
+
+## 5.5.1
+
+### Patch Changes
+
+-   [#4120](https://github.com/refinedev/refine/pull/4120) [`1f310bd7b69`](https://github.com/refinedev/refine/commit/1f310bd7b6900f534bb57db90d3fc8a6ea4364c9) Thanks [@aliemir](https://github.com/aliemir)! - Fix broken `useModalForm` and `useDrawerForm` with `create` actions.
+
+## 5.5.0
+
+### Minor Changes
+
+-   [#4072](https://github.com/refinedev/refine/pull/4072) [`fad40e6237f`](https://github.com/refinedev/refine/commit/fad40e6237f06f99b1a5cad943cf34cf693a78fb) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - `<Layout>` is deprecated. use `<ThemedLayout>` instead with 100% backward compatibility. - https://refine.dev/docs/api-reference/antd/components/antd-themed-layout
+
+### Patch Changes
+
+-   [#4114](https://github.com/refinedev/refine/pull/4114) [`afdaed3dd83`](https://github.com/refinedev/refine/commit/afdaed3dd8357d6106ed5a4e524d82cfcceaf7ec) Thanks [@aliemir](https://github.com/aliemir)! - Updated `useModalForm` and `useDrawerForm` hook's `show` method to check if there's an `id` present or provided. If there is, it will continue to show the modal/drawer. If not, the modal/drawer will not show. (Resolves #4062)
+
+## 5.4.0
+
+### Minor Changes
+
+-   [#4072](https://github.com/refinedev/refine/pull/4072) [`fad40e6237f`](https://github.com/refinedev/refine/commit/fad40e6237f06f99b1a5cad943cf34cf693a78fb) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - `<Layout>` is deprecated. use `<ThemedLayout>` instead with 100% backward compatibility. - https://refine.dev/docs/api-reference/antd/components/antd-themed-layout
+
+### Patch Changes
+
+-   [#4114](https://github.com/refinedev/refine/pull/4114) [`afdaed3dd83`](https://github.com/refinedev/refine/commit/afdaed3dd8357d6106ed5a4e524d82cfcceaf7ec) Thanks [@aliemir](https://github.com/aliemir)! - Updated `useModalForm` and `useDrawerForm` hook's `show` method to check if there's an `id` present or provided. If there is, it will continue to show the modal/drawer. If not, the modal/drawer will not show. (Resolves #4062)
+
+## 5.3.14
+
+### Patch Changes
+
+-   [#4035](https://github.com/refinedev/refine/pull/4035) [`e0c75450f97`](https://github.com/refinedev/refine/commit/e0c75450f970878fea0ace7db63548c7ba1a1688) Thanks [@salihozdemir](https://github.com/salihozdemir)! - - Re-extending the `SuccessErrorNotification` and `LiveProps` types removed
+    -   `useEditableTable`'s `successNotification` and `errorNotification` props now work according to the mutation result instead of the query result
+
+## 5.3.13
+
+### Patch Changes
+
+-   [#4035](https://github.com/refinedev/refine/pull/4035) [`e0c75450f97`](https://github.com/refinedev/refine/commit/e0c75450f970878fea0ace7db63548c7ba1a1688) Thanks [@salihozdemir](https://github.com/salihozdemir)! - - Re-extending the `SuccessErrorNotification` and `LiveProps` types removed
+    -   `useEditableTable`'s `successNotification` and `errorNotification` props now work according to the mutation result instead of the query result
+
+## 5.3.12
+
+### Patch Changes
+
+-   [#4024](https://github.com/refinedev/refine/pull/4024) [`dc6d2311eb7`](https://github.com/refinedev/refine/commit/dc6d2311eb76a458f828fb15fe26fae1c75bc95a) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Added: `wrapperStyles` prop to `<ThemedTitle>` component to allow for custom styles to be passed in.
+
+    -   Added: `textDecoration: none` to `<ThemedTitle>` component.
+
+## 5.3.11
+
+### Patch Changes
+
+-   [#4024](https://github.com/refinedev/refine/pull/4024) [`dc6d2311eb7`](https://github.com/refinedev/refine/commit/dc6d2311eb76a458f828fb15fe26fae1c75bc95a) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Added: `wrapperStyles` prop to `<ThemedTitle>` component to allow for custom styles to be passed in.
+
+    -   Added: `textDecoration: none` to `<ThemedTitle>` component.
+
+## 5.3.10
+
+### Patch Changes
+
+-   [#3997](https://github.com/refinedev/refine/pull/3997) [`f027d8a53b8`](https://github.com/refinedev/refine/commit/f027d8a53b8475f63f3557733c81b9ef040ed0ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the logs out.
+
+        -   The `<ThemedSider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+-   [#3974](https://github.com/refinedev/refine/pull/3974) [`4dcc20d6a60`](https://github.com/refinedev/refine/commit/4dcc20d6a6097bb81a094e4bcb630504b2a055d2) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Deprecated the `WelcomePage` component. It'll be used from `@refinedev/core` instead.
+
+## 5.3.9
+
+### Patch Changes
+
+-   [#3997](https://github.com/refinedev/refine/pull/3997) [`f027d8a53b8`](https://github.com/refinedev/refine/commit/f027d8a53b8475f63f3557733c81b9ef040ed0ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the logs out.
+
+        -   The `<ThemedSider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+-   [#3974](https://github.com/refinedev/refine/pull/3974) [`4dcc20d6a60`](https://github.com/refinedev/refine/commit/4dcc20d6a6097bb81a094e4bcb630504b2a055d2) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Deprecated the `WelcomePage` component. It'll be used from `@refinedev/core` instead.
+
+## 5.3.8
+
+### Patch Changes
+
+-   [#3975](https://github.com/refinedev/refine/pull/3975) [`b1e6e32f9a1`](https://github.com/refinedev/refine/commit/b1e6e32f9a19e8f26f95d41c942f90e96ed68372) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the logs out.
+
+        -   The `<ThemedSider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+    -   `<RefineThemes>` colors updated to match the new theme colors.
+
+-   Updated dependencies [[`2798f715361`](https://github.com/refinedev/refine/commit/2798f715361c5fd407d09429d94b05b602b50397)]:
+    -   @refinedev/ui-types@1.5.0
+
+## 5.3.7
+
+### Patch Changes
+
+-   [#3975](https://github.com/refinedev/refine/pull/3975) [`b1e6e32f9a1`](https://github.com/refinedev/refine/commit/b1e6e32f9a19e8f26f95d41c942f90e96ed68372) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the logs out.
+
+        -   The `<ThemedSider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+    -   `<RefineThemes>` colors updated to match the new theme colors.
+
+-   Updated dependencies [[`2798f715361`](https://github.com/refinedev/refine/commit/2798f715361c5fd407d09429d94b05b602b50397)]:
+    -   @refinedev/ui-types@1.4.0
+
+## 5.3.6
+
+### Patch Changes
+
+-   [#3967](https://github.com/refinedev/refine/pull/3967) [`67603562695`](https://github.com/refinedev/refine/commit/67603562695707e9d0bf16908d480fddf6fce7f1) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: `<ThemedTitle>` font size was overridden by parent because `<Space>` has the default font size.
+
+## 5.3.5
+
+### Patch Changes
+
+-   [#3967](https://github.com/refinedev/refine/pull/3967) [`67603562695`](https://github.com/refinedev/refine/commit/67603562695707e9d0bf16908d480fddf6fce7f1) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: `<ThemedTitle>` font size was overridden by parent because `<Space>` has the default font size.
+
+## 5.3.4
+
+### Patch Changes
+
+-   [#3949](https://github.com/refinedev/refine/pull/3949) [`836b06a2f67`](https://github.com/refinedev/refine/commit/836b06a2f67ec966247c422e42e11f39e6167288) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: <ThemedTitle> font size was "14px". Updated to "20px" on `<AuthPage>`, "14px" on `<ThemedSider>`.
+
+-   [#3956](https://github.com/refinedev/refine/pull/3956) [`c54714ed9ab`](https://github.com/refinedev/refine/commit/c54714ed9abd289edef9a6bef4e85b234a6b6e55) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed an issue where the `<NumberField />` component would throw an error if the `value` prop was set to `undefined`.
+
+## 5.3.3
+
+### Patch Changes
+
+-   [#3949](https://github.com/refinedev/refine/pull/3949) [`836b06a2f67`](https://github.com/refinedev/refine/commit/836b06a2f67ec966247c422e42e11f39e6167288) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: <ThemedTitle> font size was "14px". Updated to "20px" on `<AuthPage>`, "14px" on `<ThemedSider>`.
+
+-   [#3956](https://github.com/refinedev/refine/pull/3956) [`c54714ed9ab`](https://github.com/refinedev/refine/commit/c54714ed9abd289edef9a6bef4e85b234a6b6e55) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed an issue where the `<NumberField />` component would throw an error if the `value` prop was set to `undefined`.
+
+## 5.3.2
+
+### Patch Changes
+
+-   [#3931](https://github.com/refinedev/refine/pull/3931) [`d92c8e82868`](https://github.com/refinedev/refine/commit/d92c8e82868519ea7fd37678b74c1d6207a73bcd) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added missing `autoSubmitClose`, `autoResetForm`, and `defaultVisible` props to `useDrawerForm` hook.
+
+-   [#3911](https://github.com/refinedev/refine/pull/3911) [`5f9c70ebf2f`](https://github.com/refinedev/refine/commit/5f9c70ebf2faeea21eef97286ae7391bb77abfa9) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed `autoSubmitClose` and `autoResetForm` props of `useModalForm` hook to work properly.
+
+-   [#3931](https://github.com/refinedev/refine/pull/3931) [`d92c8e82868`](https://github.com/refinedev/refine/commit/d92c8e82868519ea7fd37678b74c1d6207a73bcd) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added `autoSubmitClose`, `autoResetForm`, and `defaultVisible` props to `useDrawerForm` hook.
+
+-   [#3948](https://github.com/refinedev/refine/pull/3948) [`b4950503334`](https://github.com/refinedev/refine/commit/b495050333464224f34851c9c57ffab457a3f120) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the delete button or logs out, when the form is dirty.
+
+    -   The `<DeleteButton>` already has a confirmation dialog, so the alert was removed.
+    -   The `<Sider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+## 5.3.1
+
+### Patch Changes
+
+-   [#3931](https://github.com/refinedev/refine/pull/3931) [`d92c8e82868`](https://github.com/refinedev/refine/commit/d92c8e82868519ea7fd37678b74c1d6207a73bcd) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added missing `autoSubmitClose`, `autoResetForm`, and `defaultVisible` props to `useDrawerForm` hook.
+
+-   [#3911](https://github.com/refinedev/refine/pull/3911) [`5f9c70ebf2f`](https://github.com/refinedev/refine/commit/5f9c70ebf2faeea21eef97286ae7391bb77abfa9) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed `autoSubmitClose` and `autoResetForm` props of `useModalForm` hook to work properly.
+
+-   [#3931](https://github.com/refinedev/refine/pull/3931) [`d92c8e82868`](https://github.com/refinedev/refine/commit/d92c8e82868519ea7fd37678b74c1d6207a73bcd) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Added `autoSubmitClose`, `autoResetForm`, and `defaultVisible` props to `useDrawerForm` hook.
+
+-   [#3948](https://github.com/refinedev/refine/pull/3948) [`b4950503334`](https://github.com/refinedev/refine/commit/b495050333464224f34851c9c57ffab457a3f120) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed the unsaved changes dialog is popping up unexpectedly when the user clicks the delete button or logs out, when the form is dirty.
+
+    -   The `<DeleteButton>` already has a confirmation dialog, so the alert was removed.
+    -   The `<Sider>`'s `onClick` handler was changed to use the `window.confirm` API to manage the confirmation dialog.
+
+## 5.3.0
+
+### Minor Changes
+
+-   [#3912](https://github.com/refinedev/refine/pull/3912) [`0ffe70308b2`](https://github.com/refinedev/refine/commit/0ffe70308b24d2d70695399fb0a1b7b76bcf2ccb) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - `RefineThemes` added. It contains predefined colors for the antd components.
+
+    ```tsx
+    import { RefineThemes } from "@refinedev/antd";
+    import { Refine } from "@refinedev/core";
+    import dataProvider from "@refinedev/simple-rest";
+
+    const App = () => {
+        // ---
+
+        return (
+            <ConfigProvider
+                theme={{
+                    token: RefineThemes.Magenta.token,
+                }}
+            >
+                <Refine dataProvider={dataProvider("YOUR_API_URL")}>
+                    {/** your app here */}
+                </Refine>
+            </ConfigProvider>
+        );
+    };
+    ```
+
+    -   default title with icon added to `AuthPage`. It uses `ThemedTitle` component from `@refinedev/antd`. You can remove it by setting `title` prop to `false`.
+
+    ```tsx
+    <AuthPage title={false} />
+    ```
+
+    -   `title` prop added to `AuthPage`'s `renderContent` prop to use in the custom content.
+
+    ```tsx
+    <AuthPage
+        renderContent={(content: React.ReactNode, title: React.ReactNode) => {
+            return (
+                <div
+                    style={{
+                        display: "flex",
+                        flexDirection: "column",
+                        justifyContent: "center",
+                        alignItems: "center",
+                    }}
+                >
+                    {title}
+                    <h1 style={{ color: "white" }}>Extra Header</h1>
+                    {content}
+                    <h1 style={{ color: "white" }}>Extra Footer</h1>
+                </div>
+            );
+        }}
+    />
+    ```
+
+    -   `<ThemedLayout>`, `<ThemedSider>`, `<ThemedTitle>`, `<ThemedHeader>` created to use theme colors.
+
+    -   `<EditButton>` in `<Show>` type changed to `primary`.
+    -   `<CreateButton>` type changed to `primary`.
+
+    -   `<AuthPage>` component uses colors from the theme.
+    -   `<ThemedTitle>` added to `AuthPage`
+
+### Patch Changes
+
+-   Updated dependencies [[`0ffe70308b2`](https://github.com/refinedev/refine/commit/0ffe70308b24d2d70695399fb0a1b7b76bcf2ccb)]:
+    -   @refinedev/ui-types@1.3.0
+
+## 5.2.0
+
+### Minor Changes
+
+-   [#3912](https://github.com/refinedev/refine/pull/3912) [`0ffe70308b2`](https://github.com/refinedev/refine/commit/0ffe70308b24d2d70695399fb0a1b7b76bcf2ccb) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - - `RefineThemes` added. It contains predefined colors for the antd components.
+
+    ```tsx
+    import { RefineThemes } from "@refinedev/antd";
+    import { Refine } from "@refinedev/core";
+    import dataProvider from "@refinedev/simple-rest";
+
+    const App = () => {
+        // ---
+
+        return (
+            <ConfigProvider
+                theme={{
+                    token: RefineThemes.Magenta.token,
+                }}
+            >
+                <Refine dataProvider={dataProvider("YOUR_API_URL")}>
+                    {/** your app here */}
+                </Refine>
+            </ConfigProvider>
+        );
+    };
+    ```
+
+    -   default title with icon added to `AuthPage`. It uses `ThemedTitle` component from `@refinedev/antd`. You can remove it by setting `title` prop to `false`.
+
+    ```tsx
+    <AuthPage title={false} />
+    ```
+
+    -   `title` prop added to `AuthPage`'s `renderContent` prop to use in the custom content.
+
+    ```tsx
+    <AuthPage
+        renderContent={(content: React.ReactNode, title: React.ReactNode) => {
+            return (
+                <div
+                    style={{
+                        display: "flex",
+                        flexDirection: "column",
+                        justifyContent: "center",
+                        alignItems: "center",
+                    }}
+                >
+                    {title}
+                    <h1 style={{ color: "white" }}>Extra Header</h1>
+                    {content}
+                    <h1 style={{ color: "white" }}>Extra Footer</h1>
+                </div>
+            );
+        }}
+    />
+    ```
+
+    -   `<ThemedLayout>`, `<ThemedSider>`, `<ThemedTitle>`, `<ThemedHeader>` created to use theme colors.
+
+    -   `<EditButton>` in `<Show>` type changed to `primary`.
+    -   `<CreateButton>` type changed to `primary`.
+
+    -   `<AuthPage>` component uses colors from the theme.
+    -   `<ThemedTitle>` added to `AuthPage`
+
+### Patch Changes
+
+-   Updated dependencies [[`0ffe70308b2`](https://github.com/refinedev/refine/commit/0ffe70308b24d2d70695399fb0a1b7b76bcf2ccb)]:
+    -   @refinedev/ui-types@1.2.0
+
+## 5.1.2
+
+### Patch Changes
+
+-   [#3885](https://github.com/refinedev/refine/pull/3885) [`5495ab7028e`](https://github.com/refinedev/refine/commit/5495ab7028e9cbd576948f2b347e6d00ddc87728) Thanks [@omeraplak](https://github.com/omeraplak)! - fix: header text color
+
+## 5.1.1
+
+### Patch Changes
+
+-   [#3885](https://github.com/refinedev/refine/pull/3885) [`5495ab7028e`](https://github.com/refinedev/refine/commit/5495ab7028e9cbd576948f2b347e6d00ddc87728) Thanks [@omeraplak](https://github.com/omeraplak)! - fix: header text color
+
+## 5.1.0
+
+### Minor Changes
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    Updated the components to match the changes in routing system of `@refinedev/core`.
+
+    ## `meta` property in components
+
+    This includes `meta` props in buttons and `Sider` component. `meta` property can be used to pass additional parameters to the navigation paths.
+
+    For a `posts` resource definition like this:
+
+    ```tsx
+    <Refine
+        resources={[
+            {
+                name: "posts",
+                list: "/posts",
+                show: "/:authorId/posts/:id",
+            }
+        ]}
+    >
+    ```
+
+    You can pass `authorId` to the `ShowButton` component like this:
+
+    ```tsx
+    <ShowButton resource="posts" id="1" meta={{ authorId: 123 }}>
+    ```
+
+    This will navigate to `/123/posts/1` path.
+
+    ## `syncWithLocation` support in `useDrawerForm` and `useModalForm` hooks
+
+    `useDrawerForm` and `useModalForm` hooks now support `syncWithLocation` prop. This prop can be used to sync the visibility state of them with the location via query params.
+
+    You can pass a boolean or an object with `key` and `syncId` properties.
+
+    -   `key` is used to define the query param key. Default value is inferred from the resource and the action. For example `posts-create` for `posts` resource and `create` action.
+
+    -   `syncId` is used to include the `id` property in the query param key. Default value is `false`. This is useful for `edit` and `clone` actions.
+
+    ## Removed props
+
+    `ignoreAccessControlProvider` prop is removed from buttons.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    Updated buttons with `resource` property. `resourceNameOrRouteName` is now deprecated but kept working until next major version.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    All **Ant Design** components re-exported from `@refinedev/antd` have been removed. You should import them from `antd` package directly.
+
+    If the package is not installed, you should install it with your package manager:
+
+    ```bash
+    npm install antd
+    # or
+    pnpm add antd
+    # or
+    yarn add antd
+    ```
+
+    After that, you can import components from `antd` package directly like below:
+
+    ```diff
+    -import { useTable, SaveButton, Button, Form, Input, Select } from "@refinedev/antd";
+
+    +import { useTable, SaveButton } from "@refinedev/antd";
+    +import { Button, Form, Input, Select } from "antd";
+    ```
+
+    <br />
+
+    `Icons` are also removed from `@refinedev/antd`. So, you should import icons from `@ant-design/icons` package directly.
+
+    If the package is not installed, you should install it with your package manager:
+
+    ```bash
+    npm install @ant-design/icons
+    # or
+    pnpm add @ant-design/icons
+    # or
+    yarn add @ant-design/icons
+    ```
+
+    After that, you can import icons from `@ant-design/icons` package directly like below:
+
+    ```diff
+    -import { Icons } from "@refinedev/antd";
+    -const { EditOutlined } = Icons;
+
+    + import { EditOutlined } from "@ant-design/icons";
+    ```
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    Upgrade `@ant-design/icons` to `^5.0.1` for consistency.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+
+    -   `useCheckboxGroup`'s `sort` prop is now deprecated. Use `sorters` prop instead.
+
+    ```diff
+    useCheckboxGroup({
+    -    sort,
+    +    sorters,
+    })
+    ```
+
+    -   `useSelect`'s `sort` prop is now deprecated. Use `sorters` prop instead.
+
+    ```diff
+    useSelect({
+    -    sort,
+    +    sorters,
+    })
+    ```
+
+    -   `useRadioGroup`'s `sort` prop is now deprecated. Use `sorters` prop instead.
+
+    ```diff
+    useRadioGroup({
+    -    sort,
+    +    sorters,
+    })
+    ```
+
+    -   `useImport`'s `resourceName` prop is now deprecated. Use `resource` prop instead.
+
+    ```diff
+    useImport({
+    -    resourceName,
+    +    resource,
+    })
+    ```
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+
+    -   `<ReadyPage>` isnow deprecated.
+    -   Created a `<WelcomePage>` component to welcome users.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    Added legacy auth provider and new auth provider support to all components and hooks.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+
+    ## 🪄 Migrating your project automatically with refine-codemod ✨
+
+    [`@refinedev/codemod`](https://github.com/refinedev/refine/tree/master/packages/codemod) package handles the breaking changes for your project automatically, without any manual steps. It migrates your project from `3.x.x` to `4.x.x`.
+
+    Just `cd` into root folder of your project (where `package.json` is contained) and run this command:
+
+    ```sh
+    npx @refinedev/codemod@latest refine3-to-refine4
+    ```
+
+    And it's done. Now your project uses `refine@4.x.x`.
+
+    ## 📝 Changelog
+
+    Deprecated `useMenu` removed from `@refinedev/antd` package. Use `useMenu` from `@refinedev/core` package instead.
+
+    ```diff
+    - import { useMenu } from "@refinedev/antd";
+    + import { useMenu } from "@refinedev/core";
+    ```
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+    **Moving to the `@refinedev` scope 🎉🎉**
+
+    Moved to the `@refinedev` scope and updated our packages to use the new scope. From now on, all packages will be published under the `@refinedev` scope with their new names.
+
+    Now, we're also removing the `refine` prefix from all packages. So, the `@pankod/refine-core` package is now `@refinedev/core`, `@pankod/refine-antd` is now `@refinedev/antd`, and so on.
+
+-   Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
+
+    ## `useTable` hook
+
+    `useTable` return values and properties are updated.
+
+    -   `initialCurrent` and `initialPageSize` props are now deprecated. Use `pagination` prop instead.
+    -   To ensure backward compatibility, `initialCurrent` and `initialPageSize` props will work as before.
+
+        ```diff
+        useTable({
+        -    initialCurrent,
+        -    initialPageSize,
+        +    pagination: {
+        +        current,
+        +        pageSize,
+        +    },
+        })
+        ```
+
+    -   `hasPagination` prop is now deprecated. Use `pagination.mode` instead.
+    -   To ensure backward compatibility, `hasPagination` prop will work as before.
+
+        ```diff
+        useTable({
+        -    hasPagination,
+        +    pagination: {
+        +        mode: "off" | "server" | "client",
+        +    },
+        })
+        ```
+
+    -   `initialSorter` and `permanentSorter` props are now deprecated. Use `sorters.initial` and `sorters.permanent` instead.
+    -   To ensure backward compatibility, `initialSorter` and `permanentSorter` props will work as before.
+
+        ```diff
+        useTable({
+        -    initialSorter,
+        -    permanentSorter,
+        +    sorters: {
+        +        initial,
+        +        permanent,
+        +    },
+        })
+        ```
+
+    -   `initialFilter`, `permanentFilter`, and `defaultSetFilterBehavior` props are now deprecated. Use `filters.initial`, `filters.permanent`, and `filters.defaultBehavior` instead.
+    -   To ensure backward compatibility, `initialFilter`, `permanentFilter`, and `defaultSetFilterBehavior` props will work as before.
+
+        ```diff
+        useTable({
+        -    initialFilter,
+        -    permanentFilter,
+        -    defaultSetFilterBehavior,
+        +    filters: {
+        +        initial,
+        +        permanent,
+        +        defaultBehavior,
+        +    },
+        })
+        ```
+
+    -   `sorter` and `setSorter` return values are now deprecated. Use `sorters` and `setSorters` instead.
+    -   To ensure backward compatibility, `sorter` and `setSorter` return values will work as before.
+
+        ```diff
+        const {
+        -   sorter,
+        +   sorters,
+        -   setSorter,
+        +   setSorters,
+        } = useTable();
+        ```
+
+    ## `useSimpleList` hook
+
+    -   Now `useSimpleList` hook will not accept all of `<List>` component properties So, you can give their props to `<List>` component directly.
+
+        ```diff
+        import { useSimpleList } from "@refinedev/antd";
+        import { List } from "antd";
+
+        const { listProps } = useSimpleList({
+            resource: "orders",
+            pagination: {
+                pageSize: 6,
+        -       simple: true,
+            },
+        });
+
+        <List
+            {...listProps}
+        +   pagination={{
+        +     ...listProps.pagination,
+        +     simple: true,
+        +   }}
+            ... // other props
+        />
+        ```
+
+    -   `initialCurrent` and `initialPageSize` props are now deprecated. Use `pagination` prop instead.
+    -   To ensure backward compatibility, `initialCurrent` and `initialPageSize` props will work as before.
+
+    -   ```diff
+        useSimpleList({
+        -    initialCurrent,
+        -    initialPageSize,
+        +    pagination: {
+        +        current,
+        +        pageSize,
+        +    },
+        })
+        ```
+
+### Patch Changes
+
+## 4.9.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+### Patch Changes
+
+-   Updated dependencies [[`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb)]:
+    -   @pankod/refine-ui-types@0.16.0
+
+## 4.8.0
+
+### Minor Changes
+
+-   [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
+
+### Patch Changes
+
+-   Updated dependencies [[`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb)]:
+    -   @pankod/refine-ui-types@0.15.0
+
+## 4.7.3
+
+### Patch Changes
+
+-   [#3606](https://github.com/refinedev/refine/pull/3606) [`00c9a5c471a`](https://github.com/refinedev/refine/commit/00c9a5c471a684169f800d65800d87cc8d6b6511) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the issue with `disabled` state in `DeleteButton`'s still opening the popover.
+
+## 4.7.2
+
+### Patch Changes
+
+-   [#3606](https://github.com/refinedev/refine/pull/3606) [`00c9a5c471a`](https://github.com/refinedev/refine/commit/00c9a5c471a684169f800d65800d87cc8d6b6511) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the issue with `disabled` state in `DeleteButton`'s still opening the popover.
+
+## 4.7.1
+
+### Patch Changes
+
+-   [#3399](https://github.com/refinedev/refine/pull/3399) [`22b44a857a8`](https://github.com/refinedev/refine/commit/22b44a857a8ede3473965ab6baff70fc8ae31332) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Fix `useTable` hook error return type.
+
+## 4.7.0
+
+### Minor Changes
+
+-   [#3324](https://github.com/refinedev/refine/pull/3324) [`9bfb34749bc`](https://github.com/refinedev/refine/commit/9bfb34749bc8ddaaf80ccffbd0ad6d0a4487309b) Thanks [@aliemir](https://github.com/aliemir)! - Added the ability to pass mutation options to `useMutation` hooks in mutation hooks:
+    -   `useForm`
+    -   `useStepsForm`
+    -   `useModalForm`
+    -   `useDrawerForm`
+
+## 4.6.0
+
+### Minor Changes
+
+-   [#3324](https://github.com/refinedev/refine/pull/3324) [`9bfb34749bc`](https://github.com/refinedev/refine/commit/9bfb34749bc8ddaaf80ccffbd0ad6d0a4487309b) Thanks [@aliemir](https://github.com/aliemir)! - Added the ability to pass mutation options to `useMutation` hooks in mutation hooks:
+    -   `useForm`
+    -   `useStepsForm`
+    -   `useModalForm`
+    -   `useDrawerForm`
+
+## 4.5.0
+
+### Minor Changes
+
+-   [#3294](https://github.com/refinedev/refine/pull/3294) [`3c9c8c07d21`](https://github.com/refinedev/refine/commit/3c9c8c07d2183595402d70a3a2bc49093778e183) Thanks [@aliemir](https://github.com/aliemir)! - Remove `getContainer: false` from `useModalForm` and `useDrawerForm` and let it fallback to the default value. Users wanting to override the default value can still do so by passing `getContainer` prop to the `Modal` and `Drawer` components.
+
+## 4.4.0
+
+### Minor Changes
+
+-   [#3294](https://github.com/refinedev/refine/pull/3294) [`3c9c8c07d21`](https://github.com/refinedev/refine/commit/3c9c8c07d2183595402d70a3a2bc49093778e183) Thanks [@aliemir](https://github.com/aliemir)! - Remove `getContainer: false` from `useModalForm` and `useDrawerForm` and let it fallback to the default value. Users wanting to override the default value can still do so by passing `getContainer` prop to the `Modal` and `Drawer` components.
+
+## 4.3.0
+
+### Minor Changes
+
+-   [#3285](https://github.com/refinedev/refine/pull/3285) [`cc2c1f042bf`](https://github.com/refinedev/refine/commit/cc2c1f042bf43ae20c58745cccc815c337e17ae7) Thanks [@omeraplak](https://github.com/omeraplak)! - Added exports for new [`<App />`](https://ant.design/components/app), [`<QrCode />`](https://ant.design/components/qrcode) and [`<Watermark />`](https://ant.design/components/watermark) components.
+
+## 4.2.0
+
+### Minor Changes
+
+-   [#3285](https://github.com/refinedev/refine/pull/3285) [`cc2c1f042bf`](https://github.com/refinedev/refine/commit/cc2c1f042bf43ae20c58745cccc815c337e17ae7) Thanks [@omeraplak](https://github.com/omeraplak)! - Added exports for new [`<App />`](https://ant.design/components/app), [`<QrCode />`](https://ant.design/components/qrcode) and [`<Watermark />`](https://ant.design/components/watermark) components.
+
+## 4.1.5
+
+### Patch Changes
+
+-   [#3273](https://github.com/refinedev/refine/pull/3273) [`a30ba43cce2`](https://github.com/refinedev/refine/commit/a30ba43cce27279deaab60c000dac0537552f7c7) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Set the `theme="dark"` of the `Menu` component in `Sider` by default.
+
+-   [`a8d3f648a28`](https://github.com/refinedev/refine/commit/a8d3f648a282329cac04c1dd4b736864d6fbf756) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed onClick event type of the `<Button />` component
+
+## 4.1.4
+
+### Patch Changes
+
+-   [`a8d3f648a28`](https://github.com/refinedev/refine/commit/a8d3f648a282329cac04c1dd4b736864d6fbf756) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed onClick event type of the `<Button />` component
+-   [#3273](https://github.com/refinedev/refine/pull/3273) [`a30ba43cce2`](https://github.com/refinedev/refine/commit/a30ba43cce27279deaab60c000dac0537552f7c7) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Set the `theme="dark"` of the `Menu` component in `Sider` by default.
+
+## 4.1.3
+
+### Patch Changes
+
+-   [#3273](https://github.com/refinedev/refine/pull/3273) [`a30ba43cce2`](https://github.com/refinedev/refine/commit/a30ba43cce27279deaab60c000dac0537552f7c7) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Set the `theme="dark"` of the `Menu` component in `Sider` by default.
+
+## 4.1.2
+
+### Patch Changes
+
+-   [#3269](https://github.com/refinedev/refine/pull/3269) [`8b86c0c4c45`](https://github.com/refinedev/refine/commit/8b86c0c4c4529dce9eef4d6e49958eb2c50c31f2) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: Wrong import and usage after `swizzling` `<Layout>` component.
+
+## 4.1.1
+
+### Patch Changes
+
+-   [#3269](https://github.com/refinedev/refine/pull/3269) [`8b86c0c4c45`](https://github.com/refinedev/refine/commit/8b86c0c4c4529dce9eef4d6e49958eb2c50c31f2) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: Wrong import and usage after `swizzling` `<Layout>` component.
+
+## 4.1.0
+
+### Minor Changes
+
+-   [#3249](https://github.com/refinedev/refine/pull/3249) [`fd2e1882e06`](https://github.com/refinedev/refine/commit/fd2e1882e060135674f53350f2fe1d22347543d7) Thanks [@rajaomariajaona](https://github.com/rajaomariajaona)! - Add ability to pass pagination values in `useTable` hook. (Resolves #3246)
+
+    -   `current`
+    -   `setCurrent`
+    -   `pageSize`
+    -   `setPageSize`
+    -   `pageCount`
+
+-   [#3121](https://github.com/refinedev/refine/pull/3121) [`214ea79c81c`](https://github.com/refinedev/refine/commit/214ea79c81c2f21573f999083612d30256be76a9) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - We've released Ant Design v5 support :tada:
+
+    ## Upgrade
+
+    ⚡️ You can easily update **refine** packages with **refine** CLI [`update`](https://refine.dev/docs/packages/documentation/cli/#update) command.
+
+    ```bash
+    npm run refine update
+    ```
+
+    > [How to add refine CLI to an existing project?](https://refine.dev/docs/packages/documentation/cli/#how-to-add-to-an-existing-project)
+
+    ### 🪄 Migrating your project automatically with Codemod ✨
+
+    `@pankod/refine-codemod` package handles the breaking changes for your project automatically, without any manual steps. It migrates your [`@pankod/refine-antd`](https://github.com/refinedev/refine/tree/next/packages/antd) version from 3.x.x to 4.x.x.
+
+    Just `cd` into root folder of your project (where `package.json` is contained) and run this command:
+
+    ```sh
+    npx @pankod/refine-codemod antd4-to-antd5
+    ```
+
+    And it's done. Now your project uses `@pankod/refine-antd@4.x.x`.
+
+    ## Changes
+
+    -   `<PageHeader>` component moved into `@ant-design/pro-components`. **refine** is using `<PageHeader>` in `<List>`, `<Create>`, `<Edit>`, `<Show>` components and added as a dependency. You don't need to install `@ant-design/pro-components` package manually.
+    -   `<Comment>` component moved into `@ant-design/compatible`.
+    -   `moment.js` is replaced with `day.js`.
+    -   `less` is removed from `antd` package.
+
+    > Please refer to [Ant Design Migration Guide](https://ant.design/docs/react/migration-v5) for detailed information.
+
+    🚨 Next.js 13 Not Supported Now
+
+    Currently `ant-design/pro-components` does not compatible with Next.js 13.
+    **refine** is using `ant-design/pro-components` as a dependency for `<PageHeader/>` component.
+
+    > [Refer to a related issue on ant-design/pro-components repository](https://github.com/ant-design/pro-components/issues/6338)
+
+## 4.0.0
+
+### Major Changes
+
+-   [#3121](https://github.com/refinedev/refine/pull/3121) [`214ea79c81c`](https://github.com/refinedev/refine/commit/214ea79c81c2f21573f999083612d30256be76a9) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - We've released Ant Design v5 support :tada:
+
+    ## Upgrade
+
+    ⚡️ You can easily update **refine** packages with **refine** CLI [`update`](https://refine.dev/docs/packages/documentation/cli/#update) command.
+
+    ```bash
+    npm run refine update
+    ```
+
+    > [How to add refine CLI to an existing project?](https://refine.dev/docs/packages/documentation/cli/#how-to-add-to-an-existing-project)
+
+    ### 🪄 Migrating your project automatically with Codemod ✨
+
+    `@pankod/refine-codemod` package handles the breaking changes for your project automatically, without any manual steps. It migrates your [`@pankod/refine-antd`](https://github.com/refinedev/refine/tree/next/packages/antd) version from 3.x.x to 4.x.x.
+
+    Just `cd` into root folder of your project (where `package.json` is contained) and run this command:
+
+    ```sh
+    npx @pankod/refine-codemod antd4-to-antd5
+    ```
+
+    And it's done. Now your project uses `@pankod/refine-antd@4.x.x`.
+
+    ## Changes
+
+    -   `<PageHeader>` component moved into `@ant-design/pro-components`. **refine** is using `<PageHeader>` in `<List>`, `<Create>`, `<Edit>`, `<Show>` components and added as a dependency. You don't need to install `@ant-design/pro-components` package manually.
+    -   `<Comment>` component moved into `@ant-design/compatible`.
+    -   `moment.js` is replaced with `day.js`.
+    -   `less` is removed from `antd` package.
+
+    > Please refer to [Ant Design Migration Guide](https://ant.design/docs/react/migration-v5) for detailed information.
+
+    🚨 Next.js 13 Not Supported Now
+
+    Currently `ant-design/pro-components` does not compatible with Next.js 13.
+    **refine** is using `ant-design/pro-components` as a dependency for `<PageHeader/>` component.
+
+    > [Refer to a related issue on ant-design/pro-components repository](https://github.com/ant-design/pro-components/issues/6338)
+
+### Minor Changes
+
+-   [#3249](https://github.com/refinedev/refine/pull/3249) [`fd2e1882e06`](https://github.com/refinedev/refine/commit/fd2e1882e060135674f53350f2fe1d22347543d7) Thanks [@rajaomariajaona](https://github.com/rajaomariajaona)! - Add ability to pass pagination values in `useTable` hook. (Resolves #3246)
+    -   `current`
+    -   `setCurrent`
+    -   `pageSize`
+    -   `setPageSize`
+    -   `pageCount`
+
+## 3.70.4
+
+### Patch Changes
+
+-   [#3252](https://github.com/refinedev/refine/pull/3252) [`cf696235d0b`](https://github.com/refinedev/refine/commit/cf696235d0bdaca8554698293e8a644131522f34) Thanks [@aliemir](https://github.com/aliemir)! - Updated `esbuild` configuration to handle `antd/lib` imports in `esm` builds. (Resolves #3187)
+
+## 3.70.3
+
+### Patch Changes
+
+-   [#3252](https://github.com/refinedev/refine/pull/3252) [`cf696235d0b`](https://github.com/refinedev/refine/commit/cf696235d0bdaca8554698293e8a644131522f34) Thanks [@aliemir](https://github.com/aliemir)! - Updated `esbuild` configuration to handle `antd/lib` imports in `esm` builds. (Resolves #3187)
+
+## 3.70.2
+
+### Patch Changes
+
+-   [#3220](https://github.com/refinedev/refine/pull/3220) [`b867497f469`](https://github.com/refinedev/refine/commit/b867497f4694a5fbd330106a39256dee3c56199b) Thanks [@aliemir](https://github.com/aliemir)! - Updated image links in `README.MD` with CDN
+
+-   Updated dependencies [[`b867497f469`](https://github.com/refinedev/refine/commit/b867497f4694a5fbd330106a39256dee3c56199b)]:
+    -   @pankod/refine-ui-types@0.14.2
+
+## 3.70.1
+
+### Patch Changes
+
+-   [#3220](https://github.com/refinedev/refine/pull/3220) [`b867497f469`](https://github.com/refinedev/refine/commit/b867497f4694a5fbd330106a39256dee3c56199b) Thanks [@aliemir](https://github.com/aliemir)! - Updated image links in `README.MD` with CDN
+
+-   Updated dependencies [[`b867497f469`](https://github.com/refinedev/refine/commit/b867497f4694a5fbd330106a39256dee3c56199b)]:
+    -   @pankod/refine-ui-types@0.14.1
+
+## 3.70.0
+
+### Minor Changes
+
+-   [#3216](https://github.com/refinedev/refine/pull/3216) [`e09eb81588e`](https://github.com/refinedev/refine/commit/e09eb81588e985e270a7b3d49f9c5b28ffcbb134) Thanks [@leapful](https://github.com/leapful)! - Support filter dropdown on number value of single Select component
+
+## 3.69.0
+
+### Minor Changes
+
+-   [#3216](https://github.com/refinedev/refine/pull/3216) [`e09eb81588e`](https://github.com/refinedev/refine/commit/e09eb81588e985e270a7b3d49f9c5b28ffcbb134) Thanks [@leapful](https://github.com/leapful)! - Support filter dropdown on number value of single Select component
+
+## 3.68.0
+
+### Minor Changes
+
+-   [#3195](https://github.com/refinedev/refine/pull/3195) [`2fdc5c2a88e`](https://github.com/refinedev/refine/commit/2fdc5c2a88e490c7f3b6ed5b562974787863931e) Thanks [@leapful](https://github.com/leapful)! - Support Date Picker component when using with Filter Dropdown
+
+## 3.67.0
+
+### Minor Changes
+
+-   [#3195](https://github.com/refinedev/refine/pull/3195) [`2fdc5c2a88e`](https://github.com/refinedev/refine/commit/2fdc5c2a88e490c7f3b6ed5b562974787863931e) Thanks [@leapful](https://github.com/leapful)! - Support Date Picker component when using with Filter Dropdown
+
+## 3.66.0
+
+### Minor Changes
+
+-   [#3159](https://github.com/refinedev/refine/pull/3159) [`af2eefb32a4`](https://github.com/refinedev/refine/commit/af2eefb32a4df157062c28125c53aa3a47f48ff8) Thanks [@aliemir](https://github.com/aliemir)! - Updated `LoginPage` and `ReadyPage` to use **refine** logos from CDN rather than bundled svg files.
+
+## 3.65.0
+
+### Minor Changes
+
+-   [#3159](https://github.com/refinedev/refine/pull/3159) [`af2eefb32a4`](https://github.com/refinedev/refine/commit/af2eefb32a4df157062c28125c53aa3a47f48ff8) Thanks [@aliemir](https://github.com/aliemir)! - Updated `LoginPage` and `ReadyPage` to use **refine** logos from CDN rather than bundled svg files.
+
+## 3.64.4
+
+### Patch Changes
+
+-   [#3128](https://github.com/refinedev/refine/pull/3128) [`db1000a7628`](https://github.com/refinedev/refine/commit/db1000a7628d910c965eb63cd1cff81ffcd4fd4a) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: `crud` components import path changed to relative path due to export issues on build.
+
+## 3.64.3
+
+### Patch Changes
+
+-   [#3128](https://github.com/refinedev/refine/pull/3128) [`db1000a7628`](https://github.com/refinedev/refine/commit/db1000a7628d910c965eb63cd1cff81ffcd4fd4a) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - Fixed: `crud` components import path changed to relative path due to export issues on build.
+
+## 3.64.2
+
+### Patch Changes
+
+-   [#3109](https://github.com/refinedev/refine/pull/3109) [`16549ed3012`](https://github.com/refinedev/refine/commit/16549ed30128750f04ae17da12024b9734d5adae) Thanks [@aliemir](https://github.com/aliemir)! - Updated `swizzle` items and their messages to include extra information and usage examples.
+
+## 3.64.1
+
+### Patch Changes
+
+-   [#3109](https://github.com/refinedev/refine/pull/3109) [`16549ed3012`](https://github.com/refinedev/refine/commit/16549ed30128750f04ae17da12024b9734d5adae) Thanks [@aliemir](https://github.com/aliemir)! - Updated `swizzle` items and their messages to include extra information and usage examples.
+
+## 3.64.0
+
+### Minor Changes
+
+-   [#3062](https://github.com/refinedev/refine/pull/3062) [`6c2ed708a9a`](https://github.com/refinedev/refine/commit/6c2ed708a9a76faddb9d27a0aca9f4ada3c270af) Thanks [@aliemir](https://github.com/aliemir)! - - Updated components and their type imports to make them compatible with `swizzle` feature.
+    -   Added `refine.config.js` to configure the `swizzle` feature.
+
+## 3.63.0
+
+### Minor Changes
+
+-   [#3062](https://github.com/refinedev/refine/pull/3062) [`6c2ed708a9a`](https://github.com/refinedev/refine/commit/6c2ed708a9a76faddb9d27a0aca9f4ada3c270af) Thanks [@aliemir](https://github.com/aliemir)! - - Updated components and their type imports to make them compatible with `swizzle` feature.
+    -   Added `refine.config.js` to configure the `swizzle` feature.
+
+## 3.62.0
+
+### Minor Changes
+
+-   [#2872](https://github.com/refinedev/refine/pull/2872) [`da3fc4a702`](https://github.com/refinedev/refine/commit/da3fc4a702b3ea50f7c1a2cc484fe6364fc3ddc0) Thanks [@TDP17](https://github.com/TDP17)! - Feat: Added ability to manage breadcrumb component globally via options
+
+    > **The option set in individual CRUD components takes priority over the global option**
+
+## 3.61.0
+
+### Minor Changes
+
+-   [#2872](https://github.com/refinedev/refine/pull/2872) [`da3fc4a702`](https://github.com/refinedev/refine/commit/da3fc4a702b3ea50f7c1a2cc484fe6364fc3ddc0) Thanks [@TDP17](https://github.com/TDP17)! - Feat: Added ability to manage breadcrumb component globally via options
+
+    > **The option set in individual CRUD components takes priority over the global option**
+
+## 3.60.0
+
+### Minor Changes
+
+-   [#2839](https://github.com/refinedev/refine/pull/2839) [`5388a338ab`](https://github.com/refinedev/refine/commit/5388a338abb9a5e03599da0a2786bea394cbc516) Thanks [@aliemir](https://github.com/aliemir)! - **Deprecation**
+
+    `ignoreAccessControlProvider` prop on buttons is deprecated. Use `accessContro.enabled` instead.
+
+    **Features**
+
+    `accessControl.enabled` prop is added to buttons to enable/disable access control for buttons.
+    `accessControl.hideIfUnauthorized` prop is added to buttons to hide the button if access is denied.
+
+-   [#2836](https://github.com/refinedev/refine/pull/2836) [`e43e9a17ae`](https://github.com/refinedev/refine/commit/e43e9a17ae0ed41e649b8026b2b04d850136dcfd) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - added locales prop to date fields
+
+### Patch Changes
+
+-   [#2838](https://github.com/refinedev/refine/pull/2838) [`f7968fa16f`](https://github.com/refinedev/refine/commit/f7968fa16f9930442e1122fe5294e350252bdd5c) Thanks [@aliemir](https://github.com/aliemir)! - Fixed #2828 - Buttons were not respecting access control when navigating to a new page. Now, if button is disabled, it will not also block the navigation not just the onClick event.
+
+-   Updated dependencies [[`476285e342`](https://github.com/refinedev/refine/commit/476285e3427c7e065892a281da529c038aee83d2), [`5388a338ab`](https://github.com/refinedev/refine/commit/5388a338abb9a5e03599da0a2786bea394cbc516), [`e43e9a17ae`](https://github.com/refinedev/refine/commit/e43e9a17ae0ed41e649b8026b2b04d850136dcfd)]:
+    -   @pankod/refine-ui-types@0.14.0
+
+## 3.59.0
+
+### Minor Changes
+
+-   [#2836](https://github.com/refinedev/refine/pull/2836) [`e43e9a17ae`](https://github.com/refinedev/refine/commit/e43e9a17ae0ed41e649b8026b2b04d850136dcfd) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - added locales prop to date fields
+
+### Patch Changes
+
+-   Updated dependencies [[`e43e9a17ae`](https://github.com/refinedev/refine/commit/e43e9a17ae0ed41e649b8026b2b04d850136dcfd)]:
+    -   @pankod/refine-ui-types@0.13.0
+
+## 3.58.0
+
+### Minor Changes
+
+-   [#2839](https://github.com/refinedev/refine/pull/2839) [`5388a338ab`](https://github.com/refinedev/refine/commit/5388a338abb9a5e03599da0a2786bea394cbc516) Thanks [@aliemir](https://github.com/aliemir)! - **Deprecation**
+
+    `ignoreAccessControlProvider` prop on buttons is deprecated. Use `accessContro.enabled` instead.
+
+    **Features**
+
+    `accessControl.enabled` prop is added to buttons to enable/disable access control for buttons.
+    `accessControl.hideIfUnauthorized` prop is added to buttons to hide the button if access is denied.
+
+### Patch Changes
+
+-   [#2838](https://github.com/refinedev/refine/pull/2838) [`f7968fa16f`](https://github.com/refinedev/refine/commit/f7968fa16f9930442e1122fe5294e350252bdd5c) Thanks [@aliemir](https://github.com/aliemir)! - Fixed #2828 - Buttons were not respecting access control when navigating to a new page. Now, if button is disabled, it will not also block the navigation not just the onClick event.
+
+-   Updated dependencies [[`476285e342`](https://github.com/refinedev/refine/commit/476285e3427c7e065892a281da529c038aee83d2), [`5388a338ab`](https://github.com/refinedev/refine/commit/5388a338abb9a5e03599da0a2786bea394cbc516)]:
+    -   @pankod/refine-ui-types@0.12.0
+
+## 3.57.0
+
+### Minor Changes
+
+-   Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
+
+    ```
+    {
+      operator: "or",
+      value: [
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "John Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 30,
+            },
+          ],
+        },
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "JR Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 1,
+            },
+          ],
+        },
+      ],
+    }
+    ```
+
+### Patch Changes
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.11.6
+
+## 3.56.0
+
+### Minor Changes
+
+-   [#2751](https://github.com/refinedev/refine/pull/2751) [`addff64c77`](https://github.com/refinedev/refine/commit/addff64c777e4c9f044a1a109cb05453e6e9f762) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
+
+    ```
+    {
+      operator: "or",
+      value: [
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "John Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 30,
+            },
+          ],
+        },
+        {
+          operator: "and",
+          value: [
+            {
+              field: "name",
+              operator: "eq",
+              value: "JR Doe",
+            },
+            {
+              field: "age",
+              operator: "eq",
+              value: 1,
+            },
+          ],
+        },
+      ],
+    }
+    ```
+
+### Patch Changes
+
+-   Updated dependencies [[`19124711a7`](https://github.com/refinedev/refine/commit/19124711a7dc23c0b0e61bc845fbd294927999da)]:
+    -   @pankod/refine-ui-types@0.11.5
+
+## 3.55.3
+
+### Patch Changes
+
+-   Fixed `providers` property empty array state in `<AuthPage />` component
+
+## 3.55.2
+
+### Patch Changes
+
+-   Fixed `providers` property empty array state in `<AuthPage />` component
+
+## 3.55.1
+
+### Patch Changes
+
+-   [#2712](https://github.com/refinedev/refine/pull/2712) [`c434055011`](https://github.com/refinedev/refine/commit/c434055011cbdd846c9f228c23987607bb828a1b) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed `providers` property empty array state in `<AuthPage />` component
+
+## 3.55.0
+
+### Minor Changes
+
+-   Added infinite loading example to antd `useSelect()`
+    `useSelect()` `fetchSize` prop is deprecated. From now [`pagination`](https://refine.dev/docs/api-reference/core/interfaceReferences/#pagination) should be used
+
+### Patch Changes
+
+-   Add AuthProps type export
+
+## 3.54.0
+
+### Minor Changes
+
+-   [#2629](https://github.com/refinedev/refine/pull/2629) [`bc89228e73`](https://github.com/refinedev/refine/commit/bc89228e73dbf373cbbbd0fbf5e6e4721224a7c5) Thanks [@bungambohlah](https://github.com/bungambohlah)! - Added infinite loading example to antd `useSelect()`
+    `useSelect()` `fetchSize` prop is deprecated. From now [`pagination`](https://refine.dev/docs/api-reference/core/interfaceReferences/#pagination) should be used
+
+### Patch Changes
+
+-   [#2666](https://github.com/refinedev/refine/pull/2666) [`8a562d2114`](https://github.com/refinedev/refine/commit/8a562d2114b7145707070e363981a4e31e02547a) Thanks [@omeraplak](https://github.com/omeraplak)! - Add AuthProps type export
+
+## 3.53.0
+
+### Minor Changes
+
+-   -   Added new <AuthPage /> component core and mantine support.
+    -   Move Auth types `@pankod/refine-ui-types` to `@pankod/refine-core`
+
+## 3.52.0
+
+### Minor Changes
+
+-   [#2627](https://github.com/refinedev/refine/pull/2627) [`c5fb45d61f`](https://github.com/refinedev/refine/commit/c5fb45d61fa7470a7a34762ad19d17e9f87e4421) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - - Added new <AuthPage /> component core and mantine support.
+    -   Move Auth types `@pankod/refine-ui-types` to `@pankod/refine-core`
+
+## 3.51.0
+
+### Minor Changes
+
+-   Deprecated `LoginPage`.
+
+    **Before**
+
+    ```tsx
+    import { LoginPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={LoginPage}
+      ...
+    />
+    ```
+
+    **After**
+
+    ```tsx
+    import { AuthPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={AuthPage}
+      ...
+    />
+    ```
+
+## 3.50.0
+
+### Minor Changes
+
+-   Deprecated `LoginPage`.
+
+    **Before**
+
+    ```tsx
+    import { LoginPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={LoginPage}
+      ...
+    />
+    ```
+
+    **After**
+
+    ```tsx
+    import { AuthPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={AuthPage}
+      ...
+    />
+    ```
+
+## 3.49.0
+
+### Minor Changes
+
+-   [#2580](https://github.com/refinedev/refine/pull/2580) [`e1ab7da6b3`](https://github.com/refinedev/refine/commit/e1ab7da6b335bad62b15a537a3ed63c9f113bd01) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Deprecated `LoginPage`.
+
+    **Before**
+
+    ```tsx
+    import { LoginPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={LoginPage}
+      ...
+    />
+    ```
+
+    **After**
+
+    ```tsx
+    import { AuthPage } from "@pankod/refine-antd";
+
+    <Refine
+      LoginPage={AuthPage}
+      ...
+    />
+    ```
+
+## 3.48.10
+
+### Patch Changes
+
+-   ReadyPage examples link fixed.
+
+## 3.48.9
+
+### Patch Changes
+
+-   [#2505](https://github.com/refinedev/refine/pull/2505) [`a4dbb63c88`](https://github.com/refinedev/refine/commit/a4dbb63c881a83e5146829130b1377e791b44469) Thanks [@salihozdemir](https://github.com/salihozdemir)! - ReadyPage examples link fixed.
+
+## 3.48.8
+
+### Patch Changes
+
+-   Updated `disabled` attribute of buttons in CRUD components according to `isLoading` prop.
+
+-   Removed redundant type inheritance
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.11.2
+
+## 3.48.7
+
+### Patch Changes
+
+-   [#2586](https://github.com/refinedev/refine/pull/2586) [`d7c8b7642b`](https://github.com/refinedev/refine/commit/d7c8b7642b7ed41a2063798e779c3cfaa09b0e7b) Thanks [@necatiozmen](https://github.com/necatiozmen)! - Removed redundant type inheritance
+
+-   Updated dependencies [[`d7c8b7642b`](https://github.com/refinedev/refine/commit/d7c8b7642b7ed41a2063798e779c3cfaa09b0e7b)]:
+    -   @pankod/refine-ui-types@0.11.1
+
+## 3.48.6
+
+### Patch Changes
+
+-   [#2585](https://github.com/refinedev/refine/pull/2585) [`e7ab42a73b`](https://github.com/refinedev/refine/commit/e7ab42a73b87625b2646864118ad25cbe31295ad) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Updated `disabled` attribute of buttons in CRUD components according to `isLoading` prop.
+
+## 3.48.5
+
+### Patch Changes
+
+-   Rename `reset-password` -> `forgot-password` on docs.
+
+## 3.48.4
+
+### Patch Changes
+
+-   Rename `reset-password` -> `forgot-password` on docs.
+
+## 3.48.3
+
+### Patch Changes
+
+-   [#2568](https://github.com/refinedev/refine/pull/2568) [`efe99f7843`](https://github.com/refinedev/refine/commit/efe99f78433c46433f137fd9581f33f4d75778e0) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Rename `reset-password` -> `forgot-password` on docs.
+
+## 3.48.2
+
+### Patch Changes
+
+-   Fixed `useModalForm` & `useStepsForm` return type
+
+## 3.48.1
+
+### Patch Changes
+
+-   [#2552](https://github.com/refinedev/refine/pull/2552) [`52cd8d633e`](https://github.com/refinedev/refine/commit/52cd8d633e57f925bb51c875aab0406e3358ec45) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed `useModalForm` & `useStepsForm` return type
+
+## 3.48.0
+
+### Minor Changes
+
+-   Add `providers` support on AuthPage register page.
+
+### Patch Changes
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.11.0
+
+## 3.47.0
+
+### Minor Changes
+
+-   [#2551](https://github.com/refinedev/refine/pull/2551) [`a65525de6f`](https://github.com/refinedev/refine/commit/a65525de6f995babfca1058e933cdbea67d6032e) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Add `providers` support on AuthPage register page.
+
+### Patch Changes
+
+-   Updated dependencies [[`a65525de6f`](https://github.com/refinedev/refine/commit/a65525de6f995babfca1058e933cdbea67d6032e)]:
+    -   @pankod/refine-ui-types@0.10.0
+
+## 3.46.4
+
+### Patch Changes
+
+-   -   Auth pages background color fixed.
+    -   Removed unused `updatePasswordLink` prop from auth pages.
+    -   Removed `onSubmit` prop from auth pages. use `formProps` instead.
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.9.2
+
+## 3.46.3
+
+### Patch Changes
+
+-   [#2524](https://github.com/refinedev/refine/pull/2524) [`27bf81bebb`](https://github.com/refinedev/refine/commit/27bf81bebb217d2944e20e79a8f7618eda0e9db7) Thanks [@biskuvit](https://github.com/biskuvit)! - - Auth pages background color fixed.
+    -   Removed unused `updatePasswordLink` prop from auth pages.
+    -   Removed `onSubmit` prop from auth pages. use `formProps` instead.
+-   Updated dependencies [[`27bf81bebb`](https://github.com/refinedev/refine/commit/27bf81bebb217d2944e20e79a8f7618eda0e9db7)]:
+    -   @pankod/refine-ui-types@0.9.1
+
+## 3.46.2
+
+### Patch Changes
+
+-   Fixed the spacing between `icon` and `breadcrumb label` in `Breadcrumb` component.
+
+## 3.46.1
+
+### Patch Changes
+
+-   [#2534](https://github.com/refinedev/refine/pull/2534) [`a9676932cc`](https://github.com/refinedev/refine/commit/a9676932ccae00f364918f163e44e73032ffa029) Thanks [@ozkalai](https://github.com/ozkalai)! - Fixed the spacing between `icon` and `breadcrumb label` in `Breadcrumb` component.
+
+## 3.46.0
+
+### Minor Changes
+
+-   Added `formProps` property support for AuthPage component
+
+    ## Usage
+
+    ```tsx
+    <AuthPage
+        type="login"
+        formProps={{
+            initialValues: {
+                email: "demo@refine.dev",
+                password: "demo",
+            },
+        }}
+    />
+    ```
+
+### Patch Changes
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.9.0
+
+## 3.45.0
+
+### Minor Changes
+
+-   [#2516](https://github.com/refinedev/refine/pull/2516) [`ad99916d6d`](https://github.com/refinedev/refine/commit/ad99916d6dbd181b857fd7df7b9619d8cac5e3e0) Thanks [@omeraplak](https://github.com/omeraplak)! - Added `formProps` property support for AuthPage component
+
+    ## Usage
+
+    ```tsx
+    <AuthPage
+        type="login"
+        formProps={{
+            initialValues: {
+                email: "demo@refine.dev",
+                password: "demo",
+            },
+        }}
+    />
+    ```
+
+### Patch Changes
+
+-   Updated dependencies [[`ad99916d6d`](https://github.com/refinedev/refine/commit/ad99916d6dbd181b857fd7df7b9619d8cac5e3e0)]:
+    -   @pankod/refine-ui-types@0.8.0
+
+## 3.44.0
+
+### Minor Changes
+
+-   Added `render` prop to `Sider` component. You can get `dashboard`, `logout` and `items` from `render` props to customize the `Sider` component.
+
+-   Added `<AuthPage>` for Ant Design. `<AuthPage>` is a component that provides a login, register, forgot password and update password pages.
+
+### Patch Changes
+
+-   Fixed version of react-router to `6.3.0`
+
+-   Passed `collapsed` prop to `render` method in `Sider` component of `@pankod/refine-antd`.
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.7.0
+
+## 3.43.1
+
+### Patch Changes
+
+-   [#2501](https://github.com/refinedev/refine/pull/2501) [`4095a578d4`](https://github.com/refinedev/refine/commit/4095a578d471254ee58412f130ac5a0f3a62880f) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed version of react-router to `6.3.0`
+
+## 3.43.0
+
+### Minor Changes
+
+-   [#2447](https://github.com/refinedev/refine/pull/2447) [`628a37a675`](https://github.com/refinedev/refine/commit/628a37a6753a778cbec5c29b698981e0157caa42) Thanks [@biskuvit](https://github.com/biskuvit)! - Added `<AuthPage>` for Ant Design. `<AuthPage>` is a component that provides a login, register, forgot password and update password pages.
+
+### Patch Changes
+
+-   Updated dependencies [[`628a37a675`](https://github.com/refinedev/refine/commit/628a37a6753a778cbec5c29b698981e0157caa42)]:
+    -   @pankod/refine-ui-types@0.6.2
+
+## 3.42.1
+
+### Patch Changes
+
+-   [#2492](https://github.com/refinedev/refine/pull/2492) [`7d5bf3023d`](https://github.com/refinedev/refine/commit/7d5bf3023d00617890ffa7f9d22b1116af15e0b9) Thanks [@ozkalai](https://github.com/ozkalai)! - Passed `collapsed` prop to `render` method in `Sider` component of `@pankod/refine-antd`.
+
+-   Updated dependencies [[`7d5bf3023d`](https://github.com/refinedev/refine/commit/7d5bf3023d00617890ffa7f9d22b1116af15e0b9)]:
+    -   @pankod/refine-ui-types@0.6.1
+
+## 3.42.0
+
+### Minor Changes
+
+-   [#2454](https://github.com/refinedev/refine/pull/2454) [`72487a4126`](https://github.com/refinedev/refine/commit/72487a4126fb7d827dccd3bcbdee9a83aa1f56af) Thanks [@ozkalai](https://github.com/ozkalai)! - Added `render` prop to `Sider` component. You can get `dashboard`, `logout` and `items` from `render` props to customize the `Sider` component.
+
+### Patch Changes
+
+-   Updated dependencies [[`72487a4126`](https://github.com/refinedev/refine/commit/72487a4126fb7d827dccd3bcbdee9a83aa1f56af)]:
+    -   @pankod/refine-ui-types@0.6.0
+
+## 3.41.0
+
+### Minor Changes
+
+-   Added support nested sorting
+
+## 3.40.0
+
+### Minor Changes
+
+-   [#2427](https://github.com/refinedev/refine/pull/2427) [`b21908e872`](https://github.com/refinedev/refine/commit/b21908e87209c3a8825991c6ab829f7c45c19e9b) Thanks [@geoffatsource](https://github.com/geoffatsource)! - Added support nested sorting
+
+## 3.39.0
+
+### Minor Changes
+
+-   Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+### Patch Changes
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.5.0
+
+## 3.38.0
+
+### Minor Changes
+
+-   [#2440](https://github.com/refinedev/refine/pull/2440) [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af) Thanks [@aliemir](https://github.com/aliemir)! - Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
+
+### Patch Changes
+
+-   Updated dependencies [[`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af), [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af)]:
+    -   @pankod/refine-ui-types@0.4.0
+
+## 3.37.11
+
+### Patch Changes
+
+-   Fix: `useStepsForm`'s `submit` function can be overridden
+
+## 3.37.10
+
+### Patch Changes
+
+-   Fix: `useStepsForm`'s `submit` function can be overridden
+
+## 3.37.9
+
+### Patch Changes
+
+-   [#2421](https://github.com/refinedev/refine/pull/2421) [`2b1c5e01b0`](https://github.com/refinedev/refine/commit/2b1c5e01b0f65b2c7558ba79539fab411480cc06) Thanks [@omeraplak](https://github.com/omeraplak)! - Fix: `useStepsForm`'s `submit` function can be overridden
+
+## 3.37.8
+
+### Patch Changes
+
+-   Fix: Wrap with [`<CanAccess />`](https://refine.dev/docs/core/components/accessControl/can-access/) component to parent sider items
+
+    ```tsx
+    <Refine
+        accessControlProvider={{
+            can: async ({ action, resource }) => {
+                // console.log({ action, resource });
+                // output: {action: "list", resource: "cms" }
+
+                return { can: true };
+            },
+        }}
+        resources={[
+            {
+                name: "CMS",
+            },
+            {
+                name: "posts",
+                parentName: "CMS",
+                list: PostList,
+            },
+        ]}
+    />
+    ```
+
+## 3.37.7
+
+### Patch Changes
+
+-   [#2411](https://github.com/refinedev/refine/pull/2411) [`c61470a2e0`](https://github.com/refinedev/refine/commit/c61470a2e00df94a211395541601fd39b63e2cff) Thanks [@omeraplak](https://github.com/omeraplak)! - Fix: Wrap with [`<CanAccess />`](https://refine.dev/docs/core/components/accessControl/can-access/) component to parent sider items
+
+    ```tsx
+    <Refine
+        accessControlProvider={{
+            can: async ({ action, resource }) => {
+                // console.log({ action, resource });
+                // output: {action: "list", resource: "cms" }
+
+                return { can: true };
+            },
+        }}
+        resources={[
+            {
+                name: "CMS",
+            },
+            {
+                name: "posts",
+                parentName: "CMS",
+                list: PostList,
+            },
+        ]}
+    />
+    ```
+
+## 3.37.6
+
+### Patch Changes
+
+-   Fix `useModalForm` hook reset issue after successful submit
+
+## 3.37.5
+
+### Patch Changes
+
+-   [#2403](https://github.com/refinedev/refine/pull/2403) [`ef8622cba3`](https://github.com/refinedev/refine/commit/ef8622cba32acc8f5edf9e4190fbe90d99e642c6) Thanks [@omeraplak](https://github.com/omeraplak)! - Fix `useModalForm` hook reset issue after successful submit
+
+## 3.37.4
+
+### Patch Changes
+
+-   Updated `<Edit/>` component's default footer buttons property wrapper with `<Space/>` component like `<Footer>
+
+## 3.37.3
+
+### Patch Changes
+
+-   Updated `<Edit/>` component's default footer buttons property wrapper with `<Space/>` component like `<Footer>
+
+## 3.37.2
+
+### Patch Changes
+
+-   Updated `<Edit/>` component's default footer buttons property wrapper with `<Space/>` component like `<Footer>
+
+## 3.37.1
+
+### Patch Changes
+
+-   [#2343](https://github.com/refinedev/refine/pull/2343) [`90b39d4f83`](https://github.com/refinedev/refine/commit/90b39d4f839dc97868b7126ffb2903e29b8bb51a) Thanks [@aliemir](https://github.com/aliemir)! - Updated `<Edit/>` component's default footer buttons property wrapper with `<Space/>` component like `<Footer>
+
+## 3.37.0
+
+### Minor Changes
+
+-   Separated `styles.min.css` file as `antd.min.css` and `reset.min.css` to make users able to turn off `reset` styles when needed.
+
+## 3.36.0
+
+### Minor Changes
+
+-   [#2312](https://github.com/refinedev/refine/pull/2312) [`ba5646c65c`](https://github.com/refinedev/refine/commit/ba5646c65cc09dee688fef1cf3a6556707754c3c) Thanks [@aliemir](https://github.com/aliemir)! - Separated `styles.min.css` file as `antd.min.css` and `reset.min.css` to make users able to turn off `reset` styles when needed.
+
+## 3.35.4
+
+### Patch Changes
+
+-   Upgraded `react-query` version to 4.
+
+## 3.35.3
+
+### Patch Changes
+
+-   [#2260](https://github.com/refinedev/refine/pull/2260) [`a97ec592df`](https://github.com/refinedev/refine/commit/a97ec592dfb6dcf5b5bd063d2d76f50ca195c20e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Upgraded `react-query` version to 4.
+
+## 3.35.2
+
+### Patch Changes
+
+-   Remove `data-testid` props from buttons in crud components to make use of button test ids presented by `@pankod/refine-ui-types` package.
+
+*   Updated `@pankod/refine-antd` and `@pankod/refine-mui` `fields` properties by using `@pankod/refine-ui-types` common `fields` types.
+
+    Updated `@pankod/refine-antd` and `@pankod/refine-mui` `fields` tests by using `@pankod/refine-ui-tests` common `fields` tests.
+
+    Updated `@pankod/refine-ui-tests` `fields` properties.
+
+-   Added `@pankod/refine-ui-tests` and `@pankod/refine-ui-types` packages. Now, all of button prop types comes from `@pankod/refine-ui-types` package and all of button tests comes from `@pankod/refine-ui-tests` package.
+
+    Thus, button types and tests are managed by `@pankod/refine-ui-types` package and `@pankod/refine-ui-tests` package.
+
+-   Updated dependencies []:
+    -   @pankod/refine-ui-types@0.3.0
+
+## 3.35.1
+
+### Patch Changes
+
+-   [#2216](https://github.com/refinedev/refine/pull/2216) [`201846c77d`](https://github.com/refinedev/refine/commit/201846c77dba07a61f0c0335716b60641430c22a) Thanks [@aliemir](https://github.com/aliemir)! - Remove `data-testid` props from buttons in crud components to make use of button test ids presented by `@pankod/refine-ui-types` package.
+
+*   [#2216](https://github.com/refinedev/refine/pull/2216) [`201846c77d`](https://github.com/refinedev/refine/commit/201846c77dba07a61f0c0335716b60641430c22a) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@pankod/refine-antd` and `@pankod/refine-mui` `fields` properties by using `@pankod/refine-ui-types` common `fields` types.
+
+    Updated `@pankod/refine-antd` and `@pankod/refine-mui` `fields` tests by using `@pankod/refine-ui-tests` common `fields` tests.
+
+    Updated `@pankod/refine-ui-tests` `fields` properties.
+
+-   [#2216](https://github.com/refinedev/refine/pull/2216) [`201846c77d`](https://github.com/refinedev/refine/commit/201846c77dba07a61f0c0335716b60641430c22a) Thanks [@aliemir](https://github.com/aliemir)! - Added `@pankod/refine-ui-tests` and `@pankod/refine-ui-types` packages. Now, all of button prop types comes from `@pankod/refine-ui-types` package and all of button tests comes from `@pankod/refine-ui-tests` package.
+
+    Thus, button types and tests are managed by `@pankod/refine-ui-types` package and `@pankod/refine-ui-tests` package.
+
+-   Updated dependencies [[`201846c77d`](https://github.com/refinedev/refine/commit/201846c77dba07a61f0c0335716b60641430c22a)]:
+    -   @pankod/refine-ui-types@0.2.0
+
+## 3.35.0
+
+### Minor Changes
+
+-   Add React@18 support 🚀
+
+### Patch Changes
+
+-   Fixed `isMobile` control in `Sider` component detecting `desktop` dimensions as `mobile` on route changes
+
+## 3.34.0
+
+### Minor Changes
+
+-   [#1718](https://github.com/refinedev/refine/pull/1718) [`b38620d842`](https://github.com/refinedev/refine/commit/b38620d84237e13212811daada7b49ee654c70eb) Thanks [@omeraplak](https://github.com/omeraplak)! - Add React@18 support 🚀
+
+### Patch Changes
+
+-   [#2255](https://github.com/refinedev/refine/pull/2255) [`b56f43529f`](https://github.com/refinedev/refine/commit/b56f43529f387ad1801e7bc0d94dfa5679bad77e) Thanks [@omeraplak](https://github.com/omeraplak)! - Fixed `isMobile` control in `Sider` component detecting `desktop` dimensions as `mobile` on route changes
+
+## 3.33.2
+
+### Patch Changes
+
+-   Updated `console.warn`'s to trigger once.
+
+## 3.33.1
+
+### Patch Changes
+
+-   [#2223](https://github.com/refinedev/refine/pull/2223) [`0a215f2000`](https://github.com/refinedev/refine/commit/0a215f2000b4069618e42efda48b8864b38129fd) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Updated `console.warn`'s to trigger once.
+
+## 3.33.0
+
+### Minor Changes
+
+-   All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.32.0
+
+### Minor Changes
+
+-   [#2217](https://github.com/refinedev/refine/pull/2217) [`b4aae00f77`](https://github.com/refinedev/refine/commit/b4aae00f77a2476d847994db21298ae25e4cf6e5) Thanks [@omeraplak](https://github.com/omeraplak)! - All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
+
+    Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
+
+## 3.31.0
+
+### Minor Changes
+
+-   **BREAKING** Updated `useStepsForm` prop `isBackValidate` with default `false` instead of `true` to achieve consistency between packages (`@pankod/refine-react-hook-form`).
+
+### Patch Changes
+
+-   Fix `useModal` hook doesn't return `modalProps`
+
+*   Added `hasPagination` support to [`useSimpleList`](https://refine.dev/docs/ui-frameworks/antd/hooks/list/useSimpleList/) hook.
+
+## 3.30.0
+
+### Minor Changes
+
+-   [#2206](https://github.com/refinedev/refine/pull/2206) [`874b05af37`](https://github.com/refinedev/refine/commit/874b05af377b995c9cea6cbcde5407a19403f53d) Thanks [@aliemir](https://github.com/aliemir)! - **BREAKING** Updated `useStepsForm` prop `isBackValidate` with default `false` instead of `true` to achieve consistency between packages (`@pankod/refine-react-hook-form`).
+
+### Patch Changes
+
+-   [#2203](https://github.com/refinedev/refine/pull/2203) [`3c80308ca1`](https://github.com/refinedev/refine/commit/3c80308ca143d11d7daeb7e9624d0138ecede42d) Thanks [@omeraplak](https://github.com/omeraplak)! - Fix `useModal` hook doesn't return `modalProps`
+
+*   [#2201](https://github.com/refinedev/refine/pull/2201) [`62c261c2a7`](https://github.com/refinedev/refine/commit/62c261c2a7eaaec77d10440f2ec37f3697d869c9) Thanks [@omeraplak](https://github.com/omeraplak)! - Added `hasPagination` support to [`useSimpleList`](https://refine.dev/docs/ui-frameworks/antd/hooks/list/useSimpleList/) hook.
+
+## 3.29.0
+
+### Minor Changes
+
+-   Added `defaultSetFilterBehavior` prop to `useTable` and `useSimpleList` hooks. Return `setFilters` and `setSorter` from `useTable` of `@pankod/refine-core`.
+
+    This feature will let `@pankod/refine-antd` users to set filters manually and change filter setter logic (defaults to `merge`).
+
+### Patch Changes
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.44.0
+
+## 3.28.0
+
+### Minor Changes
+
+-   [#2168](https://github.com/refinedev/refine/pull/2168) [`a9196ffe2d`](https://github.com/refinedev/refine/commit/a9196ffe2de8bfe266be2cac1ac05eab039d0fb7) Thanks [@aliemir](https://github.com/aliemir)! - Added `defaultSetFilterBehavior` prop to `useTable` and `useSimpleList` hooks. Return `setFilters` and `setSorter` from `useTable` of `@pankod/refine-core`.
+
+    This feature will let `@pankod/refine-antd` users to set filters manually and change filter setter logic (defaults to `merge`).
+
+### Patch Changes
+
+-   Updated dependencies [[`4d5f6b25e5`](https://github.com/refinedev/refine/commit/4d5f6b25e51cf773e08a0ce0b93a3680e692564a)]:
+    -   @pankod/refine-core@3.43.0
+
+## 3.27.6
+
+### Patch Changes
+
+-   Fixed the `Unhandled Promise` error on console for `useForm` with failed requests (Resolves #2156).
+
+    This fix only catches the errors triggered by submitting the form, requests by invoking `onFinish` function should be handled by the user.
+
+## 3.27.5
+
+### Patch Changes
+
+-   [#2161](https://github.com/refinedev/refine/pull/2161) [`8490f3c38f`](https://github.com/refinedev/refine/commit/8490f3c38f8a7136a7dc396f3105334da8068b0b) Thanks [@aliemir](https://github.com/aliemir)! - Fixed the `Unhandled Promise` error on console for `useForm` with failed requests (Resolves #2156).
+
+    This fix only catches the errors triggered by submitting the form, requests by invoking `onFinish` function should be handled by the user.
+
+## 3.27.4
+
+### Patch Changes
+
+-   Removed unused cases in `useFileUploadState` and fixed conflicting type in `antd#UploadFileStatus` interface.
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.40.0
+
+## 3.27.3
+
+### Patch Changes
+
+-   [#2135](https://github.com/refinedev/refine/pull/2135) [`cf90324cb4`](https://github.com/refinedev/refine/commit/cf90324cb4043cb8c0fae79c15e9c17c2bda8044) Thanks [@aliemir](https://github.com/aliemir)! - Removed unused cases in `useFileUploadState` and fixed conflicting type in `antd#UploadFileStatus` interface.
+
+-   Updated dependencies [[`868bb943ad`](https://github.com/refinedev/refine/commit/868bb943adc42d80a7904e2acbd6397d097ad4e2)]:
+    -   @pankod/refine-core@3.39.0
+
+## 3.27.2
+
+### Patch Changes
+
+-   Add `dataProviderName` property for `<RefreshButton>` and `<DeleteButton>` in `<Edit>` and `<Show>` CRUD components - #2096
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.38.0
+
+## 3.27.1
+
+### Patch Changes
+
+-   [#2106](https://github.com/refinedev/refine/pull/2106) [`10a20d8714`](https://github.com/refinedev/refine/commit/10a20d87142b694bc9c02afaee5b4fe6c5853c5a) Thanks [@omeraplak](https://github.com/omeraplak)! - Add `dataProviderName` property for `<RefreshButton>` and `<DeleteButton>` in `<Edit>` and `<Show>` CRUD components - #2096
+
+-   Updated dependencies [[`9d77c63a92`](https://github.com/refinedev/refine/commit/9d77c63a925dca0133b3e83974dff486a2233017), [`98966b586f`](https://github.com/refinedev/refine/commit/98966b586f6febd8669065b5b453a8e441f76bc1)]:
+    -   @pankod/refine-core@3.37.0
+
+## 3.27.0
+
+### Minor Changes
+
+-   Updated `useTable` hook with `hasPagination` to enable/disable pagination.
+
+    **Implementation**
+
+    Updated the `useTable` accordingly to the changes in the `useTable` of `@pankod/refine-core`. `hasPagination` property is being send directly to the `useTable` of `@pankod/refine-core` to disable pagination.
+
+    **Use Cases**
+
+    In some data providers, some of the resources might not support pagination which was not supported prior to these changes. To handle the pagination on the client-side or to disable completely, users can set `hasPagination` to `false`.
+
+### Patch Changes
+
+-   Fixed `<Link>` usage in packages.
+
+    ```diff
+    - <Link href={route} to={route}>
+    -    {label}
+    - </Link>
+    + <Link to={route}>{label}</Link>
+    ```
+
+    We used to have to pass `href` and `to` for Next.js and React applications, now we just need to pass `to`. **refine** router providers handle for us.
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.36.0
+
+## 3.26.0
+
+### Minor Changes
+
+-   [#2050](https://github.com/refinedev/refine/pull/2050) [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5) Thanks [@ozkalai](https://github.com/ozkalai)! - Updated `useTable` hook with `hasPagination` to enable/disable pagination.
+
+    **Implementation**
+
+    Updated the `useTable` accordingly to the changes in the `useTable` of `@pankod/refine-core`. `hasPagination` property is being send directly to the `useTable` of `@pankod/refine-core` to disable pagination.
+
+    **Use Cases**
+
+    In some data providers, some of the resources might not support pagination which was not supported prior to these changes. To handle the pagination on the client-side or to disable completely, users can set `hasPagination` to `false`.
+
+### Patch Changes
+
+-   [#2061](https://github.com/refinedev/refine/pull/2061) [`0237725cf3`](https://github.com/refinedev/refine/commit/0237725cf32923f7d24d3f0c9a2994de30baa921) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Fixed `<Link>` usage in packages.
+
+    ```diff
+    - <Link href={route} to={route}>
+    -    {label}
+    - </Link>
+    + <Link to={route}>{label}</Link>
+    ```
+
+    We used to have to pass `href` and `to` for Next.js and React applications, now we just need to pass `to`. **refine** router providers handle for us.
+
+-   Updated dependencies [[`ecde34a9b3`](https://github.com/refinedev/refine/commit/ecde34a9b38ef5667fa863f9ebb9dcb1cfff1651), [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5)]:
+    -   @pankod/refine-core@3.35.0
+
+## 3.25.10
+
+### Patch Changes
+
+-   Updated the `id` parameter type to [`BaseKey`](https://refine.dev/docs/core/interfaceReferences/#basekey) for `show` function in [`useModalForm`](https://refine.dev/docs/packages/react-hook-form/useModalForm/) hook
+
+*   Updated the `id` type to `BaseKey` for `isEditing` and `editButtonProps` properties in `useEditableTable` hook.
+
+*   Updated dependencies []:
+    -   @pankod/refine-core@3.34.2
+
+## 3.25.9
+
+### Patch Changes
+
+-   [#2059](https://github.com/refinedev/refine/pull/2059) [`326341c94e`](https://github.com/refinedev/refine/commit/326341c94edb7f6a1507900506caccc60a386229) Thanks [@omeraplak](https://github.com/omeraplak)! - Updated the `id` parameter type to [`BaseKey`](https://refine.dev/docs/core/interfaceReferences/#basekey) for `show` function in [`useModalForm`](https://refine.dev/docs/packages/react-hook-form/useModalForm/) hook
+
+*   [#2052](https://github.com/refinedev/refine/pull/2052) [`cbb09e5b22`](https://github.com/refinedev/refine/commit/cbb09e5b22add54d7dccf180cd17c9019d32ed44) Thanks [@omeraplak](https://github.com/omeraplak)! - Updated the `id` type to `BaseKey` for `isEditing` and `editButtonProps` properties in `useEditableTable` hook.
+
+*   Updated dependencies [[`0338ce9d6b`](https://github.com/refinedev/refine/commit/0338ce9d6bee673b76a18cf9e6ad480fd9928e09)]:
+    -   @pankod/refine-core@3.34.1
+
+## 3.25.8
+
+### Patch Changes
+
+-   Fix missing behavior for dashboard item in _deprecated_ `useMenu`
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.32.0
+
+## 3.25.7
+
+### Patch Changes
+
+-   [#2009](https://github.com/refinedev/refine/pull/2009) [`5b893a9bff`](https://github.com/refinedev/refine/commit/5b893a9bff707d90b0f898a52d46a7154108b0a0) Thanks [@aliemir](https://github.com/aliemir)! - Fix missing behavior for dashboard item in _deprecated_ `useMenu`
+
+-   Updated dependencies [[`498c425a0e`](https://github.com/refinedev/refine/commit/498c425a0e069b6b972a344ff32af46852306c71), [`498c425a0e`](https://github.com/refinedev/refine/commit/498c425a0e069b6b972a344ff32af46852306c71), [`498c425a0e`](https://github.com/refinedev/refine/commit/498c425a0e069b6b972a344ff32af46852306c71), [`5b893a9bff`](https://github.com/refinedev/refine/commit/5b893a9bff707d90b0f898a52d46a7154108b0a0)]:
+    -   @pankod/refine-core@3.31.0
+
+## 3.25.6
+
+### Patch Changes
+
+-   Update `key`s in `<Sider/>` component to use `route`
+
+*   Deprecated `useMenu` from `@pankod/refine-antd` and replaced with the `useMenu` from `@pankod/refine-core`
+
+*   Updated dependencies []:
+    -   @pankod/refine-core@3.30.0
+
+## 3.25.6
+
+### Patch Changes
+
+-   Could not stop `e.preventDefault()` redirection in Next.js `<Link>` component. So we added in `e.stopPropagation()` for [Ant Design Buttons](https://refine.dev/docs/ui-frameworks/antd/components/buttons/clone-button/) and [Material UI Buttons](https://refine.dev/docs/ui-frameworks/mui/components/buttons/clone-button/)
+
+## 3.25.5
+
+### Patch Changes
+
+-   [#1945](https://github.com/refinedev/refine/pull/1945) [`592a401924`](https://github.com/refinedev/refine/commit/592a40192482cf88108348ed21db437e6d304a43) Thanks [@omeraplak](https://github.com/omeraplak)! - Could not stop `e.preventDefault()` redirection in Next.js `<Link>` component. So we added in `e.stopPropagation()` for [Ant Design Buttons](https://refine.dev/docs/ui-frameworks/antd/components/buttons/clone-button/) and [Material UI Buttons](https://refine.dev/docs/ui-frameworks/mui/components/buttons/clone-button/)
+
+## 3.25.4
+
+### Patch Changes
+
+-   `@pankod/refine-antd` Pagination with Next.js Links breaks the app
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.29.0
+
+## 3.25.3
+
+### Patch Changes
+
+-   `@pankod/refine-antd` Pagination with Next.js Links breaks the app
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.28.0
+
+## 3.25.2
+
+### Patch Changes
+
+-   `@pankod/refine-antd` Pagination with Next.js Links breaks the app
+
+-   Updated dependencies []:
+    -   @pankod/refine-core@3.27.0
+
+## 3.25.1
+
+### Patch Changes
+
+-   [#1897](https://github.com/refinedev/refine/pull/1897) [`b1636033fa`](https://github.com/refinedev/refine/commit/b1636033faee2b5eacbad413e2d1f975316e97cb) Thanks [@aliemir](https://github.com/aliemir)! - `@pankod/refine-antd` Pagination with Next.js Links breaks the app
+
+## 3.23.2
+
+### Patch Changes
+
+-   [#1873](https://github.com/refinedev/refine/pull/1873) [`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc) Thanks [@aliemir](https://github.com/aliemir)! - Removed dummy default values from internal contexts.
+    Updated contexts:
+
+    -   Auth
+    -   Access Control
+    -   Notification
+    -   Translation (i18n)
+    -   unsavedWarn
+
+    **BREAKING:** `useGetLocale` hook now can return `undefined` instead of a fallback value of `en` in cases of `i18nProvider` being `undefined`.
+
+-   Updated dependencies [[`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc)]:
+    -   @pankod/refine-core@3.23.2
+
+## 3.23.1
+
+### Patch Changes
+
+-   [#1865](https://github.com/refinedev/refine/pull/1865) [`5c3392ccd1`](https://github.com/refinedev/refine/commit/5c3392ccd1eff70dae1479557eede8c246b76edc) Thanks [@omeraplak](https://github.com/omeraplak)! - Fix #1858 `useTable` creating nested `<a>` tag in Pagination component
+
+-   Updated dependencies [[`3281378b11`](https://github.com/refinedev/refine/commit/3281378b119c698be3ae4ecb3866b40b883494d8)]:
+    -   @pankod/refine-core@3.23.1
+
+## 3.23.0
+
+### Minor Changes
+
+-   [#1843](https://github.com/refinedev/refine/pull/1843) [`31850119e0`](https://github.com/refinedev/refine/commit/31850119e069b93f0b5146b039a86e736164383e) Thanks [@salihozdemir](https://github.com/salihozdemir)! - Add `useBreadcrumb` hook and `Breadrumb` component for `@pankod/refine-antd` package
+
+### Patch Changes
+
+-   Updated dependencies [[`31850119e0`](https://github.com/refinedev/refine/commit/31850119e069b93f0b5146b039a86e736164383e)]:
+    -   @pankod/refine-core@3.23.0

+ 71 - 0
packages/antd/README.md

@@ -0,0 +1,71 @@
+<div align="center" style="margin: 30px;">
+    <a href="https://refine.dev">
+    <img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
+    </a>
+</div>
+
+<br/>
+
+<div align="center">
+    <a href="https://refine.dev">Home Page</a> |
+    <a href="https://discord.gg/refine">Discord</a> |
+    <a href="https://refine.dev/examples/">Examples</a> |
+    <a href="https://refine.dev/blog/">Blog</a> |
+    <a href="https://refine.dev/docs/">Documentation</a>
+
+<br/>
+<br/>
+
+[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
+[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
+
+<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
+
+</div>
+
+<br/>
+
+<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
+
+<br/>
+
+It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
+
+</div>
+
+# Ant Design integration for refine
+
+[Ant Design](https://ant.design/) is a React.js UI library that contains easy-to-use components that are useful for building interactive user interfaces.
+
+[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
+
+refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
+
+## Installation & Usage
+
+```
+npm install @refinedev/antd antd
+```
+
+```tsx
+import { ThemedLayoutV2 } from "@refinedev/antd";
+
+import "@refinedev/antd/dist/reset.css";
+
+const App = () => {
+  return (
+    <Refine
+    /* ... */
+    >
+      <ThemedLayoutV2>{/* ... */}</ThemedLayoutV2>
+    </Refine>
+  );
+};
+```
+
+## Documentation
+
+- For more detailed information and usage, refer to the [refine Ant Design documentation](https://refine.dev/docs/api-reference/antd/).
+- [Refer to complete refine tutorial with Ant Design](https://refine.dev/docs/tutorial/introduction/select-framework/)
+- [Refer to documentation for more info about refine](https://refine.dev/docs/).
+- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

+ 31 - 0
packages/antd/jest.config.js

@@ -0,0 +1,31 @@
+const { pathsToModuleNameMapper } = require("ts-jest");
+const { compilerOptions } = require("./tsconfig.json");
+
+const paths = compilerOptions.paths ? compilerOptions.paths : {};
+
+module.exports = {
+    preset: "ts-jest",
+    rootDir: "./",
+    testEnvironment: "jsdom",
+    setupFilesAfterEnv: ["<rootDir>/test/jest.setup.ts"],
+    testPathIgnorePatterns: ["<rootDir>/node_modules/"],
+    moduleNameMapper: {
+        ...pathsToModuleNameMapper(paths, { prefix: "<rootDir>/" }),
+        "\\.css$": "identity-obj-proxy",
+        "^antd/es/": "antd/lib/",
+        "^.+\\.tsx?$": [
+            "ts-jest",
+            {
+                tsconfig: "<rootDir>/tsconfig.test.json",
+            },
+        ],
+    },
+    displayName: "antd",
+    transform: {
+        "^.+\\.svg$": "<rootDir>/test/svgTransform.ts",
+    },
+    coveragePathIgnorePatterns: [
+        "<rootDir>/src/index.ts",
+        "<rootDir>/src/interfaces/",
+    ],
+};

+ 75 - 0
packages/antd/package.json

@@ -0,0 +1,75 @@
+{
+  "name": "@refinedev/antd",
+  "version": "5.37.2",
+  "description": "refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
+  "private": false,
+  "sideEffects": [
+    "*.css"
+  ],
+  "main": "dist/index.js",
+  "module": "dist/esm/index.js",
+  "typings": "dist/index.d.ts",
+  "scripts": {
+    "start": "tsup --watch --format esm,cjs,iife --legacy-output",
+    "build": "tsup --format esm,cjs,iife --minify --legacy-output",
+    "test": "jest --passWithNoTests --runInBand",
+    "prepare": "npm run build",
+    "generate-theme": "npx @emeks/antd-custom-theme-generator -w --antd ../../node_modules/antd ./src/assets/styles/custom-theme.less ./src/assets/styles/styles.min.css"
+  },
+  "peerDependencies": {
+    "@refinedev/core": "^4.46.1",
+    "@types/react": "^17.0.0 || ^18.0.0",
+    "@types/react-dom": "^17.0.0 || ^18.0.0",
+    "antd": "^5.0.5",
+    "dayjs": "^1.10.7",
+    "react": "^17.0.0 || ^18.0.0",
+    "react-dom": "^17.0.0 || ^18.0.0"
+  },
+  "devDependencies": {
+    "@refinedev/cli": "^2.16.22",
+    "@refinedev/ui-tests": "^1.14.1",
+    "@refinedev/core": "^4.46.2",
+    "@esbuild-plugins/node-resolve": "^0.1.4",
+    "@testing-library/jest-dom": "^5.16.4",
+    "@testing-library/react": "^13.1.1",
+    "@testing-library/react-hooks": "^8.0.0",
+    "@testing-library/user-event": "^14.1.1",
+    "@types/jest": "^29.2.4",
+    "@types/react": "^18.0.0",
+    "@types/react-dom": "^18.0.0",
+    "@types/testing-library__jest-dom": "^5.14.3",
+    "esbuild-copy-static-files": "^0.1.0",
+    "esbuild-plugin-inline-image": "^0.0.8",
+    "identity-obj-proxy": "^3.0.0",
+    "jest": "^29.3.1",
+    "jest-environment-jsdom": "^29.3.1",
+    "postcss": "^8.1.4",
+    "react-router-dom": "^6.8.1",
+    "ts-jest": "^29.0.3",
+    "tsup": "^6.7.0",
+    "typescript": "^4.7.4"
+  },
+  "dependencies": {
+    "@ant-design/icons": "5.0.1",
+    "@ant-design/pro-layout": "7.17.12",
+    "@refinedev/ui-types": "^1.22.4",
+    "@tanstack/react-query": "^4.10.1",
+    "antd": "^5.0.5",
+    "dayjs": "^1.10.7",
+    "react-markdown": "^6.0.1",
+    "remark-gfm": "^1.0.0",
+    "sunflower-antd": "1.0.0-beta.3",
+    "tslib": "^2.3.1"
+  },
+  "author": "refine",
+  "license": "MIT",
+  "gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/refinedev/refine.git",
+    "directory": "packages/antd"
+  },
+  "publishConfig": {
+    "access": "public"
+  }
+}

+ 629 - 0
packages/antd/refine.config.js

@@ -0,0 +1,629 @@
+const { dirname, join } = require("path");
+const {
+    getImports,
+    appendAfterImports,
+    getFileContent,
+} = require("@refinedev/cli");
+
+/** @type {import('@refinedev/cli').RefineConfig} */
+module.exports = {
+    group: "UI Framework",
+    swizzle: {
+        items: [
+            {
+                group: "Buttons",
+                label: "ShowButton",
+                files: [
+                    {
+                        src: "./src/components/buttons/show/index.tsx",
+                        dest: "./components/buttons/show.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "CreateButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below component. If you want to change it, you can run the **swizzle** command for the below component or you can use props to override the default buttons.
+                    - <List/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/create/index.tsx",
+                        dest: "./components/buttons/create.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "CloneButton",
+                files: [
+                    {
+                        src: "./src/components/buttons/clone/index.tsx",
+                        dest: "./components/buttons/clone.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "DeleteButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
+                    - <Edit/>
+                    - <List/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/delete/index.tsx",
+                        dest: "./components/buttons/delete.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "EditButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below component. If you want to change it, you can run the **swizzle** command for the below component or you can use props to override the default buttons.
+                    - <Show/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/edit/index.tsx",
+                        dest: "./components/buttons/edit.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "ExportButton",
+                files: [
+                    {
+                        src: "./src/components/buttons/export/index.tsx",
+                        dest: "./components/buttons/export.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "ImportButton",
+                files: [
+                    {
+                        src: "./src/components/buttons/import/index.tsx",
+                        dest: "./components/buttons/import.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "ListButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
+                    - <Edit/>
+                    - <Show/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/list/index.tsx",
+                        dest: "./components/buttons/list.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "RefreshButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
+                    - <Edit/>
+                    - <Show/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/refresh/index.tsx",
+                        dest: "./components/buttons/refresh.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Buttons",
+                label: "SaveButton",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
+                    - <Create/>
+                    - <Edit/>
+                `,
+                files: [
+                    {
+                        src: "./src/components/buttons/save/index.tsx",
+                        dest: "./components/buttons/save.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Basic Views",
+                label: "Create",
+                files: [
+                    {
+                        src: "./src/components/crud/create/index.tsx",
+                        dest: "./components/crud/create.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Basic Views",
+                label: "List",
+                files: [
+                    {
+                        src: "./src/components/crud/list/index.tsx",
+                        dest: "./components/crud/list.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Basic Views",
+                label: "Show",
+                files: [
+                    {
+                        src: "./src/components/crud/show/index.tsx",
+                        dest: "./components/crud/show.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Basic Views",
+                label: "Edit",
+                files: [
+                    {
+                        src: "./src/components/crud/edit/index.tsx",
+                        dest: "./components/crud/edit.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "BooleanField",
+                files: [
+                    {
+                        src: "./src/components/fields/boolean/index.tsx",
+                        dest: "./components/fields/boolean.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "DateField",
+                files: [
+                    {
+                        src: "./src/components/fields/date/index.tsx",
+                        dest: "./components/fields/date.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "EmailField",
+                files: [
+                    {
+                        src: "./src/components/fields/email/index.tsx",
+                        dest: "./components/fields/email.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "FileField",
+                files: [
+                    {
+                        src: "./src/components/fields/file/index.tsx",
+                        dest: "./components/fields/file.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "ImageField",
+                files: [
+                    {
+                        src: "./src/components/fields/image/index.tsx",
+                        dest: "./components/fields/image.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "MarkdownField",
+                files: [
+                    {
+                        src: "./src/components/fields/markdown/index.tsx",
+                        dest: "./components/fields/markdown.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "NumberField",
+                files: [
+                    {
+                        src: "./src/components/fields/number/index.tsx",
+                        dest: "./components/fields/number.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "TagField",
+                files: [
+                    {
+                        src: "./src/components/fields/tag/index.tsx",
+                        dest: "./components/fields/tag.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "TextField",
+                files: [
+                    {
+                        src: "./src/components/fields/text/index.tsx",
+                        dest: "./components/fields/text.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Fields",
+                label: "UrlField",
+                files: [
+                    {
+                        src: "./src/components/fields/url/index.tsx",
+                        dest: "./components/fields/url.tsx",
+                    },
+                ],
+            },
+            {
+                group: "Pages",
+                label: "ErrorPage",
+                message: `
+                **\`Info:\`**
+                If you want to see an example of error page in use, you can refer to the documentation at https://refine.dev/docs/packages/documentation/routers
+                `,
+                files: [
+                    {
+                        src: "./src/components/pages/error/index.tsx",
+                        dest: "./components/pages/error.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for remove RefineErorrPageProps
+                            const refineErrorPagePropsRegex =
+                                /React\.FC<RefineErrorPageProps>/g;
+
+                            newContent = newContent.replace(
+                                refineErrorPagePropsRegex,
+                                "React.FC",
+                            );
+
+                            return newContent;
+                        },
+                    },
+                ],
+            },
+            {
+                group: "Pages",
+                label: "AuthPage",
+                message: `
+                **\`Info:\`**
+                If you want to see examples of authentication pages in use, you can refer to the documentation at https://refine.dev/docs/packages/documentation/routers
+                `,
+                files: [
+                    {
+                        src: "./src/components/pages/auth/index.tsx",
+                        dest: "./components/pages/auth/index.tsx",
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/forgotPassword/index.tsx",
+                        dest: "./components/pages/auth/components/forgotPassword.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for change style import path
+                            const styleImportRegex = /"\.\.\/styles";/g;
+
+                            newContent = newContent.replace(
+                                styleImportRegex,
+                                `"./styles";`,
+                            );
+
+                            return newContent;
+                        },
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/login/index.tsx",
+                        dest: "./components/pages/auth/components/login.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for change style import path
+                            const styleImportRegex = /"\.\.\/styles";/g;
+
+                            newContent = newContent.replace(
+                                styleImportRegex,
+                                `"./styles";`,
+                            );
+
+                            return newContent;
+                        },
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/register/index.tsx",
+                        dest: "./components/pages/auth/components/register.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for change style import path
+                            const styleImportRegex = /"\.\.\/styles";/g;
+
+                            newContent = newContent.replace(
+                                styleImportRegex,
+                                `"./styles";`,
+                            );
+
+                            return newContent;
+                        },
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/updatePassword/index.tsx",
+                        dest: "./components/pages/auth/components/updatePassword.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for change style import path
+                            const styleImportRegex = /"\.\.\/styles";/g;
+
+                            newContent = newContent.replace(
+                                styleImportRegex,
+                                `"./styles";`,
+                            );
+
+                            return newContent;
+                        },
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/index.tsx",
+                        dest: "./components/pages/auth/components/index.tsx",
+                    },
+                    {
+                        src: "./src/components/pages/auth/components/styles.ts",
+                        dest: "./components/pages/auth/components/styles.ts",
+                    },
+                ],
+            },
+            {
+                group: "Other",
+                label: "Breadcrumb",
+                message: `
+                **\`Warning:\`**
+                This component is used in the below components. If you want to change it, you can use props to override the default breadcrumb or you can manage globally with the **options** prop to the **<Refine/>** component.
+                    - <Edit/>
+                    - <List/>
+                    - <Show/>
+                    - <Create/>
+
+                **\`Passing Breadcrumb Globally:\`**
+
+                \`\`\`
+                // title: App.tsx
+                import { Breadcrumb } from "components/breadcrumb";
+
+                const App = () => {
+                    return (
+                        <Refine
+                            options={{
+                                breadcrumb: <Breadcrumb />
+                                /* ... */
+                            }}
+                            /* ... */
+                        />
+                    );
+                }
+                \`\`\`
+                `,
+                files: [
+                    {
+                        src: "./src/components/breadcrumb/index.tsx",
+                        dest: "./components/breadcrumb.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+
+                            // for remove type export
+                            const breadcrumbPropsExportRegex =
+                                /export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;?/g;
+
+                            newContent = newContent.replace(
+                                breadcrumbPropsExportRegex,
+                                `import { BreadcrumbProps } from "@refinedev/antd";`,
+                            );
+
+                            // change the breadcrumb import path
+                            const breadcrumbImportRegex =
+                                /BreadcrumbProps as AntdBreadcrumbProps,/g;
+
+                            newContent = newContent.replace(
+                                breadcrumbImportRegex,
+                                "",
+                            );
+
+                            return newContent;
+                        },
+                    },
+                ],
+            },
+            {
+                group: "Other",
+                label: "ThemedLayoutV2",
+                message: `
+                **\`Warning:\`**
+                If you want to change the default layout;
+                You should pass layout related components to the **<ThemedLayoutV2 />** component's props.
+
+                \`\`\`
+                // title: App.tsx
+                import { ThemedLayoutV2 } from "components/layout";
+                import { ThemedHeaderV2 } from "components/layout/header";
+                import { ThemedSiderV2 } from "components/layout/sider";
+                import { ThemedTitleV2 } from "components/layout/title";
+
+                const App = () => {
+                    return (
+                        <Refine
+                            /* ... */
+                        >
+                            <ThemedLayoutV2 Header={ThemedHeaderV2} Sider={ThemedSiderV2} Title={ThemedTitleV2}>
+                                /* ... */
+                            </ThemedLayoutV2>
+                        </Refine>
+                    );
+                }
+                \`\`\`
+                `,
+                files: [
+                    {
+                        src: "./src/components/themedLayoutV2/sider/index.tsx",
+                        dest: "./components/layout/sider.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+                            const imports = getImports(content);
+
+                            imports.map((importItem) => {
+                                // handle @components import replacement
+                                if (
+                                    importItem.importPath === "@components" ||
+                                    importItem.importPath === "@hooks"
+                                ) {
+                                    const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
+
+                                    newContent = newContent.replace(
+                                        importItem.statement,
+                                        newStatement,
+                                    );
+                                }
+
+                                // add content of ./styles.ts and remove import
+                                if (importItem.importPath === "./styles") {
+                                    newContent = newContent.replace(
+                                        importItem.statement,
+                                        "",
+                                    );
+
+                                    let appending = "";
+
+                                    try {
+                                        const stylesContent = getFileContent(
+                                            join(
+                                                dirname(
+                                                    "./src/components/themedLayoutV2/sider/index.tsx",
+                                                ),
+                                                "/styles.ts",
+                                            ),
+                                            "utf-8",
+                                        ).replace("export const", "const");
+
+                                        appending = stylesContent;
+                                    } catch (err) {
+                                        // console.log(err);
+                                    }
+
+                                    newContent = appendAfterImports(
+                                        newContent,
+                                        appending,
+                                    );
+                                }
+                            });
+
+                            return newContent;
+                        },
+                    },
+                    {
+                        src: "./src/components/themedLayoutV2/header/index.tsx",
+                        dest: "./components/layout/header.tsx",
+                    },
+                    {
+                        src: "./src/components/themedLayoutV2/title/index.tsx",
+                        dest: "./components/layout/title.tsx",
+                    },
+                    {
+                        src: "./src/components/themedLayoutV2/index.tsx",
+                        dest: "./components/layout/index.tsx",
+                        transform: (content) => {
+                            let newContent = content;
+                            const imports = getImports(content);
+
+                            imports.map((importItem) => {
+                                // handle @components import replacement
+                                if (
+                                    importItem.importPath === "@components" ||
+                                    importItem.importPath === "@contexts" ||
+                                    importItem.importPath === "@hooks"
+                                ) {
+                                    const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
+
+                                    newContent = newContent.replace(
+                                        importItem.statement,
+                                        newStatement,
+                                    );
+                                }
+                            });
+
+                            return newContent;
+                        },
+                    },
+                ],
+            },
+        ],
+        transform: (content) => {
+            let newContent = content;
+            const imports = getImports(content);
+
+            imports.map((importItem) => {
+                if (importItem.importPath === "@components") {
+                    const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
+
+                    newContent = newContent.replace(
+                        importItem.statement,
+                        newStatement,
+                    );
+                }
+
+                // for ui-types
+                if (importItem.importPath === "@refinedev/ui-types") {
+                    newContent = newContent.replace(importItem.statement, "");
+
+                    // prop is data-testid
+                    // remove data-testid={*} from props
+                    const testIdPropRegex = /data-testid={.*?}/g;
+
+                    newContent = newContent.replace(testIdPropRegex, "");
+                }
+
+                // for prop types
+                if (
+                    importItem.importPath === "../types" ||
+                    importItem.importPath === "./types"
+                ) {
+                    const newStatement = `import type ${importItem.namedImports} from "@refinedev/antd";`;
+
+                    newContent = newContent.replace(
+                        importItem.statement,
+                        newStatement,
+                    );
+                }
+            });
+
+            return newContent;
+        },
+    },
+};

+ 254 - 0
packages/antd/src/assets/styles/reset.css

@@ -0,0 +1,254 @@
+/* stylelint-disable */
+html,
+body {
+    width: 100%;
+    height: 100%;
+}
+input::-ms-clear,
+input::-ms-reveal {
+    display: none;
+}
+*,
+*::before,
+*::after {
+    box-sizing: border-box;
+}
+html {
+    font-family: sans-serif;
+    line-height: 1.15;
+    -webkit-text-size-adjust: 100%;
+    -ms-text-size-adjust: 100%;
+    -ms-overflow-style: scrollbar;
+    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+@-ms-viewport {
+    width: device-width;
+}
+body {
+    margin: 0;
+}
+[tabindex="-1"]:focus {
+    outline: none;
+}
+hr {
+    box-sizing: content-box;
+    height: 0;
+    overflow: visible;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+    margin-top: 0;
+    margin-bottom: 0.5em;
+    font-weight: 500;
+}
+p {
+    margin-top: 0;
+    margin-bottom: 1em;
+}
+abbr[title],
+abbr[data-original-title] {
+    -webkit-text-decoration: underline dotted;
+    text-decoration: underline;
+    text-decoration: underline dotted;
+    border-bottom: 0;
+    cursor: help;
+}
+address {
+    margin-bottom: 1em;
+    font-style: normal;
+    line-height: inherit;
+}
+input[type="text"],
+input[type="password"],
+input[type="number"],
+textarea {
+    -webkit-appearance: none;
+}
+ol,
+ul,
+dl {
+    margin-top: 0;
+    margin-bottom: 1em;
+}
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+    margin-bottom: 0;
+}
+dt {
+    font-weight: 500;
+}
+dd {
+    margin-bottom: 0.5em;
+    margin-left: 0;
+}
+blockquote {
+    margin: 0 0 1em;
+}
+dfn {
+    font-style: italic;
+}
+b,
+strong {
+    font-weight: bolder;
+}
+small {
+    font-size: 80%;
+}
+sub,
+sup {
+    position: relative;
+    font-size: 75%;
+    line-height: 0;
+    vertical-align: baseline;
+}
+sub {
+    bottom: -0.25em;
+}
+sup {
+    top: -0.5em;
+}
+pre,
+code,
+kbd,
+samp {
+    font-size: 1em;
+    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
+        monospace;
+}
+pre {
+    margin-top: 0;
+    margin-bottom: 1em;
+    overflow: auto;
+}
+figure {
+    margin: 0 0 1em;
+}
+img {
+    vertical-align: middle;
+    border-style: none;
+}
+a,
+area,
+button,
+[role="button"],
+input:not([type="range"]),
+label,
+select,
+summary,
+textarea {
+    touch-action: manipulation;
+}
+table {
+    border-collapse: collapse;
+}
+caption {
+    padding-top: 0.75em;
+    padding-bottom: 0.3em;
+    text-align: left;
+    caption-side: bottom;
+}
+input,
+button,
+select,
+optgroup,
+textarea {
+    margin: 0;
+    color: inherit;
+    font-size: inherit;
+    font-family: inherit;
+    line-height: inherit;
+}
+button,
+input {
+    overflow: visible;
+}
+button,
+select {
+    text-transform: none;
+}
+button,
+html [type="button"],
+[type="reset"],
+[type="submit"] {
+    -webkit-appearance: button;
+}
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+    padding: 0;
+    border-style: none;
+}
+input[type="radio"],
+input[type="checkbox"] {
+    box-sizing: border-box;
+    padding: 0;
+}
+input[type="date"],
+input[type="time"],
+input[type="datetime-local"],
+input[type="month"] {
+    -webkit-appearance: listbox;
+}
+textarea {
+    overflow: auto;
+    resize: vertical;
+}
+fieldset {
+    min-width: 0;
+    margin: 0;
+    padding: 0;
+    border: 0;
+}
+legend {
+    display: block;
+    width: 100%;
+    max-width: 100%;
+    margin-bottom: 0.5em;
+    padding: 0;
+    color: inherit;
+    font-size: 1.5em;
+    line-height: inherit;
+    white-space: normal;
+}
+progress {
+    vertical-align: baseline;
+}
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+    height: auto;
+}
+[type="search"] {
+    outline-offset: -2px;
+    -webkit-appearance: none;
+}
+[type="search"]::-webkit-search-cancel-button,
+[type="search"]::-webkit-search-decoration {
+    -webkit-appearance: none;
+}
+::-webkit-file-upload-button {
+    font: inherit;
+    -webkit-appearance: button;
+}
+output {
+    display: inline-block;
+}
+summary {
+    display: list-item;
+}
+template {
+    display: none;
+}
+[hidden] {
+    display: none !important;
+}
+mark {
+    padding: 0.2em;
+    background-color: #feffe6;
+}

+ 7 - 0
packages/antd/src/components/autoSaveIndicator/index.spec.tsx

@@ -0,0 +1,7 @@
+import { autoSaveIndicatorTests } from "@refinedev/ui-tests";
+
+import { AutoSaveIndicator } from "./";
+
+describe("AutoSaveIndicator", () => {
+    autoSaveIndicatorTests.bind(this)(AutoSaveIndicator);
+});

+ 86 - 0
packages/antd/src/components/autoSaveIndicator/index.tsx

@@ -0,0 +1,86 @@
+import React from "react";
+import {
+    AutoSaveIndicatorProps,
+    useTranslate,
+    AutoSaveIndicator as AutoSaveIndicatorCore,
+} from "@refinedev/core";
+import { Typography, theme } from "antd";
+import {
+    EllipsisOutlined,
+    SyncOutlined,
+    CheckCircleOutlined,
+    ExclamationCircleOutlined,
+} from "@ant-design/icons";
+
+export const AutoSaveIndicator: React.FC<AutoSaveIndicatorProps> = ({
+    status,
+    elements: {
+        success = (
+            <Message
+                key="autoSave.success"
+                defaultMessage="saved"
+                icon={<CheckCircleOutlined />}
+            />
+        ),
+        error = (
+            <Message
+                key="autoSave.error"
+                defaultMessage="auto save failure"
+                icon={<ExclamationCircleOutlined />}
+            />
+        ),
+        loading = (
+            <Message
+                key="autoSave.loading"
+                defaultMessage="saving..."
+                icon={<SyncOutlined />}
+            />
+        ),
+        idle = (
+            <Message
+                key="autoSave.idle"
+                defaultMessage="waiting for changes"
+                icon={<EllipsisOutlined />}
+            />
+        ),
+    } = {},
+}) => {
+    return (
+        <AutoSaveIndicatorCore
+            status={status}
+            elements={{
+                success,
+                error,
+                loading,
+                idle,
+            }}
+        />
+    );
+};
+
+const Message = ({
+    key,
+    defaultMessage,
+    icon,
+}: {
+    key: string;
+    defaultMessage: string;
+    icon: React.ReactNode;
+}) => {
+    const translate = useTranslate();
+    const { useToken } = theme;
+    const { token } = useToken();
+
+    return (
+        <Typography.Text
+            style={{
+                marginRight: 5,
+                color: token.colorTextTertiary,
+                fontSize: ".8rem",
+            }}
+        >
+            {translate(key, defaultMessage)}
+            <span style={{ marginLeft: ".2rem" }}>{icon}</span>
+        </Typography.Text>
+    );
+};

+ 53 - 0
packages/antd/src/components/breadcrumb/index.spec.tsx

@@ -0,0 +1,53 @@
+import React, { ReactNode } from "react";
+import { Route, Routes } from "react-router-dom";
+import { breadcrumbTests } from "@refinedev/ui-tests";
+
+import { render, TestWrapper, ITestWrapperProps, act } from "@test";
+import { Breadcrumb } from "./";
+
+const renderBreadcrumb = (
+    children: ReactNode,
+    wrapperProps: ITestWrapperProps = {},
+) => {
+    return render(
+        <Routes>
+            <Route path="/:resource/:action" element={children} />
+        </Routes>,
+        {
+            wrapper: TestWrapper(wrapperProps),
+        },
+    );
+};
+
+const DummyDashboard = () => <div>Dashboard</div>;
+
+describe("Breadcrumb", () => {
+    beforeAll(() => {
+        jest.spyOn(console, "warn").mockImplementation(jest.fn());
+    });
+
+    breadcrumbTests.bind(this)(Breadcrumb);
+
+    it("should render home icon", async () => {
+        const { container } = renderBreadcrumb(<Breadcrumb />, {
+            resources: [{ name: "posts" }],
+            routerInitialEntries: ["/posts/create"],
+            DashboardPage: DummyDashboard,
+        });
+
+        expect(container.querySelector("svg")).toBeTruthy();
+    });
+
+    it("should not render home icon with 'showhHome' props", async () => {
+        const { container } = renderBreadcrumb(
+            <Breadcrumb showHome={false} />,
+            {
+                resources: [{ name: "posts" }],
+                routerInitialEntries: ["/posts/create"],
+                DashboardPage: DummyDashboard,
+            },
+        );
+
+        expect(container.querySelector("svg")).toBeFalsy();
+    });
+});

+ 87 - 0
packages/antd/src/components/breadcrumb/index.tsx

@@ -0,0 +1,87 @@
+import React from "react";
+import {
+    useBreadcrumb,
+    useLink,
+    useRefineContext,
+    useRouterContext,
+    useRouterType,
+    useResource,
+    matchResourceFromRoute,
+} from "@refinedev/core";
+import { RefineBreadcrumbProps } from "@refinedev/ui-types";
+
+import {
+    Breadcrumb as AntdBreadcrumb,
+    BreadcrumbProps as AntdBreadcrumbProps,
+} from "antd";
+import { HomeOutlined } from "@ant-design/icons";
+
+export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;
+
+export const Breadcrumb: React.FC<BreadcrumbProps> = ({
+    breadcrumbProps,
+    showHome = true,
+    hideIcons = false,
+    meta,
+}) => {
+    const routerType = useRouterType();
+    const { breadcrumbs } = useBreadcrumb({
+        meta,
+    });
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+    const { hasDashboard } = useRefineContext();
+
+    const { resources } = useResource();
+
+    const rootRouteResource = matchResourceFromRoute("/", resources);
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    if (breadcrumbs.length === 1) {
+        return null;
+    }
+
+    const breadCrumbItems = breadcrumbs.map(({ label, icon, href }) => ({
+        key: `breadcrumb-item-${label}`,
+        title: (
+            <div
+                style={{
+                    display: "flex",
+                    alignItems: "center",
+                    justifyContent: "center",
+                    gap: 4,
+                }}
+            >
+                {!hideIcons && icon}
+                {href ? (
+                    <ActiveLink to={href}>{label}</ActiveLink>
+                ) : (
+                    <span>{label}</span>
+                )}
+            </div>
+        ),
+    }));
+
+    const getBreadcrumbItems = () => {
+        if (showHome && (hasDashboard || rootRouteResource.found)) {
+            return [
+                {
+                    key: "breadcrumb-item-home",
+                    title: (
+                        <ActiveLink to="/">
+                            {rootRouteResource?.resource?.meta?.icon ?? (
+                                <HomeOutlined />
+                            )}
+                        </ActiveLink>
+                    ),
+                },
+                ...breadCrumbItems,
+            ];
+        }
+
+        return breadCrumbItems;
+    };
+
+    return <AntdBreadcrumb items={getBreadcrumbItems()} {...breadcrumbProps} />;
+};

+ 7 - 0
packages/antd/src/components/buttons/clone/index.spec.tsx

@@ -0,0 +1,7 @@
+import { buttonCloneTests } from "@refinedev/ui-tests";
+
+import { CloneButton } from "./";
+
+describe("Clone Button", () => {
+    buttonCloneTests.bind(this)(CloneButton);
+});

+ 117 - 0
packages/antd/src/components/buttons/clone/index.tsx

@@ -0,0 +1,117 @@
+import React, { useContext } from "react";
+import { Button } from "antd";
+import { PlusSquareOutlined } from "@ant-design/icons";
+import {
+    useCan,
+    useNavigation,
+    useTranslate,
+    useResource,
+    useRouterContext,
+    useRouterType,
+    useLink,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonTestIds,
+    RefineButtonClassNames,
+} from "@refinedev/ui-types";
+
+import { CloneButtonProps } from "../types";
+
+/**
+ * `<CloneButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button> component`}.
+ * It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#clone `clone`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation useNavigation} under the hood.
+ * It can be useful when redirecting the app to the create page with the record id route of resource.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/clone-button} for more details.
+ */
+export const CloneButton: React.FC<CloneButtonProps> = ({
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    resource: resourceNameFromProps,
+    recordItemId,
+    hideText = false,
+    accessControl,
+    meta,
+    children,
+    onClick,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const { cloneUrl: generateCloneUrl } = useNavigation();
+    const routerType = useRouterType();
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    const translate = useTranslate();
+
+    const { id, resource } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "create",
+        params: { id: recordItemId ?? id, resource },
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+    });
+
+    const createButtonDisabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const cloneUrl =
+        resource && (recordItemId || id)
+            ? generateCloneUrl(resource, recordItemId! ?? id!, meta)
+            : "";
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <ActiveLink
+            to={cloneUrl}
+            replace={false}
+            onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
+                if (data?.can === false) {
+                    e.preventDefault();
+                    return;
+                }
+                if (onClick) {
+                    e.preventDefault();
+                    onClick(e);
+                }
+            }}
+        >
+            <Button
+                icon={<PlusSquareOutlined />}
+                disabled={data?.can === false}
+                title={createButtonDisabledTitle()}
+                data-testid={RefineButtonTestIds.CloneButton}
+                className={RefineButtonClassNames.CloneButton}
+                {...rest}
+            >
+                {!hideText && (children ?? translate("buttons.clone", "Clone"))}
+            </Button>
+        </ActiveLink>
+    );
+};

+ 7 - 0
packages/antd/src/components/buttons/create/index.spec.tsx

@@ -0,0 +1,7 @@
+import { buttonCreateTests } from "@refinedev/ui-tests";
+
+import { CreateButton } from "./";
+
+describe("Create Button", () => {
+    buttonCreateTests.bind(this)(CreateButton);
+});

+ 117 - 0
packages/antd/src/components/buttons/create/index.tsx

@@ -0,0 +1,117 @@
+import React, { useContext } from "react";
+import { Button } from "antd";
+import { PlusSquareOutlined } from "@ant-design/icons";
+import {
+    useNavigation,
+    useTranslate,
+    useCan,
+    useResource,
+    useRouterContext,
+    useRouterType,
+    useLink,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { CreateButtonProps } from "../types";
+
+/**
+ * <CreateButton> uses Ant Design's {@link https://ant.design/components/button/ `<Button> component`}.
+ * It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#create `create`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation `useNavigation`} under the hood.
+ * It can be useful to redirect the app to the create page route of resource}.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/create-button} for more details.
+ */
+export const CreateButton: React.FC<CreateButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    hideText = false,
+    accessControl,
+    meta,
+    children,
+    onClick,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const translate = useTranslate();
+    const routerType = useRouterType();
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    const { createUrl: generateCreateUrl } = useNavigation();
+
+    const { resource } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "create",
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+        params: {
+            resource,
+        },
+    });
+
+    const createButtonDisabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const createUrl = resource ? generateCreateUrl(resource, meta) : "";
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <ActiveLink
+            to={createUrl}
+            replace={false}
+            onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
+                if (data?.can === false) {
+                    e.preventDefault();
+                    return;
+                }
+                if (onClick) {
+                    e.preventDefault();
+                    onClick(e);
+                }
+            }}
+        >
+            <Button
+                icon={<PlusSquareOutlined />}
+                disabled={data?.can === false}
+                title={createButtonDisabledTitle()}
+                data-testid={RefineButtonTestIds.CreateButton}
+                className={RefineButtonClassNames.CreateButton}
+                type="primary"
+                {...rest}
+            >
+                {!hideText &&
+                    (children ?? translate("buttons.create", "Create"))}
+            </Button>
+        </ActiveLink>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/delete/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonDeleteTests } from "@refinedev/ui-tests";
+import { DeleteButton } from "./";
+
+describe("Delete Button", () => {
+    buttonDeleteTests.bind(this)(DeleteButton);
+});

+ 150 - 0
packages/antd/src/components/buttons/delete/index.tsx

@@ -0,0 +1,150 @@
+import React, { useContext } from "react";
+import { Button, Popconfirm } from "antd";
+import { DeleteOutlined } from "@ant-design/icons";
+import {
+    useDelete,
+    useTranslate,
+    useMutationMode,
+    useCan,
+    useResource,
+    pickNotDeprecated,
+    useWarnAboutChange,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { DeleteButtonProps } from "../types";
+
+/**
+ * `<DeleteButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} and {@link https://ant.design/components/button/ `<Popconfirm>`} components.
+ * When you try to delete something, a pop-up shows up and asks for confirmation. When confirmed it executes the `useDelete` method provided by your `dataProvider`.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/delete-button} for more details.
+ */
+export const DeleteButton: React.FC<DeleteButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    recordItemId,
+    onSuccess,
+    mutationMode: mutationModeProp,
+    children,
+    successNotification,
+    errorNotification,
+    hideText = false,
+    accessControl,
+    metaData,
+    meta,
+    dataProviderName,
+    confirmTitle,
+    confirmOkText,
+    confirmCancelText,
+    invalidates,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const translate = useTranslate();
+
+    const { id, resource, identifier } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { mutationMode: mutationModeContext } = useMutationMode();
+
+    const mutationMode = mutationModeProp ?? mutationModeContext;
+
+    const { mutate, isLoading, variables } = useDelete();
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "delete",
+        params: { id: recordItemId ?? id, resource },
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+    });
+
+    const disabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const { setWarnWhen } = useWarnAboutChange();
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <Popconfirm
+            key="delete"
+            okText={confirmOkText ?? translate("buttons.delete", "Delete")}
+            cancelText={
+                confirmCancelText ?? translate("buttons.cancel", "Cancel")
+            }
+            okType="danger"
+            title={
+                confirmTitle ?? translate("buttons.confirm", "Are you sure?")
+            }
+            okButtonProps={{ disabled: isLoading }}
+            onConfirm={(): void => {
+                if ((recordItemId ?? id) && identifier) {
+                    setWarnWhen(false);
+                    mutate(
+                        {
+                            id: recordItemId ?? id ?? "",
+                            resource: identifier,
+                            mutationMode,
+                            successNotification,
+                            errorNotification,
+                            meta: pickNotDeprecated(meta, metaData),
+                            metaData: pickNotDeprecated(meta, metaData),
+                            dataProviderName,
+                            invalidates,
+                        },
+                        {
+                            onSuccess: (value) => {
+                                onSuccess && onSuccess(value);
+                            },
+                        },
+                    );
+                }
+            }}
+            disabled={
+                typeof rest?.disabled !== "undefined"
+                    ? rest.disabled
+                    : data?.can === false
+            }
+        >
+            <Button
+                danger
+                loading={(recordItemId ?? id) === variables?.id && isLoading}
+                icon={<DeleteOutlined />}
+                title={disabledTitle()}
+                disabled={data?.can === false}
+                data-testid={RefineButtonTestIds.DeleteButton}
+                className={RefineButtonClassNames.DeleteButton}
+                {...rest}
+            >
+                {!hideText &&
+                    (children ?? translate("buttons.delete", "Delete"))}
+            </Button>
+        </Popconfirm>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/edit/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonEditTests } from "@refinedev/ui-tests";
+import { EditButton } from "./";
+
+describe("Edit Button", () => {
+    buttonEditTests.bind(this)(EditButton);
+});

+ 118 - 0
packages/antd/src/components/buttons/edit/index.tsx

@@ -0,0 +1,118 @@
+import React, { useContext } from "react";
+import { Button } from "antd";
+import { EditOutlined } from "@ant-design/icons";
+import {
+    useCan,
+    useNavigation,
+    useTranslate,
+    useResource,
+    useRouterContext,
+    useRouterType,
+    useLink,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { EditButtonProps } from "../types";
+
+/**
+ * `<EditButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} component.
+ * It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#edit `edit`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation `useNavigation`} under the hood.
+ * It can be useful when redirecting the app to the edit page with the record id route of resource}.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/edit-button} for more details.
+ */
+export const EditButton: React.FC<EditButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    recordItemId,
+    hideText = false,
+    accessControl,
+    meta,
+    children,
+    onClick,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const translate = useTranslate();
+
+    const routerType = useRouterType();
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    const { editUrl: generateEditUrl } = useNavigation();
+
+    const { id, resource } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "edit",
+        params: { id: recordItemId ?? id, resource },
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+    });
+
+    const createButtonDisabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const editUrl =
+        resource && (recordItemId ?? id)
+            ? generateEditUrl(resource, recordItemId! ?? id!, meta)
+            : "";
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <ActiveLink
+            to={editUrl}
+            replace={false}
+            onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
+                if (data?.can === false) {
+                    e.preventDefault();
+                    return;
+                }
+                if (onClick) {
+                    e.preventDefault();
+                    onClick(e);
+                }
+            }}
+        >
+            <Button
+                icon={<EditOutlined />}
+                disabled={data?.can === false}
+                title={createButtonDisabledTitle()}
+                data-testid={RefineButtonTestIds.EditButton}
+                className={RefineButtonClassNames.EditButton}
+                {...rest}
+            >
+                {!hideText && (children ?? translate("buttons.edit", "Edit"))}
+            </Button>
+        </ActiveLink>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/export/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonExportTests } from "@refinedev/ui-tests";
+import { ExportButton } from "./index";
+
+describe("<ExportButton/>", () => {
+    buttonExportTests.bind(this)(ExportButton);
+});

+ 36 - 0
packages/antd/src/components/buttons/export/index.tsx

@@ -0,0 +1,36 @@
+import React from "react";
+import { Button } from "antd";
+import { ExportOutlined } from "@ant-design/icons";
+import { useTranslate } from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { ExportButtonProps } from "../types";
+
+/**
+ * `<ExportButton>` is an Ant Design {@link https://ant.design/components/button/ `<Button>`} with a default export icon and a default text with "Export".
+ * It only has presentational value.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/export-button} for more details.
+ */
+export const ExportButton: React.FC<ExportButtonProps> = ({
+    hideText = false,
+    children,
+    ...rest
+}) => {
+    const translate = useTranslate();
+
+    return (
+        <Button
+            type="default"
+            icon={<ExportOutlined />}
+            data-testid={RefineButtonTestIds.ExportButton}
+            className={RefineButtonClassNames.ExportButton}
+            {...rest}
+        >
+            {!hideText && (children ?? translate("buttons.export", "Export"))}
+        </Button>
+    );
+};

+ 7 - 0
packages/antd/src/components/buttons/import/index.spec.tsx

@@ -0,0 +1,7 @@
+import { buttonImportTests } from "@refinedev/ui-tests";
+
+import { ImportButton } from "./index";
+
+describe("<ImportButton /> usage with useImport", () => {
+    buttonImportTests.bind(this)(ImportButton);
+});

+ 40 - 0
packages/antd/src/components/buttons/import/index.tsx

@@ -0,0 +1,40 @@
+import React from "react";
+import { Button, Upload } from "antd";
+import { ImportOutlined } from "@ant-design/icons";
+import { useTranslate } from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { ImportButtonProps } from "../types";
+
+/**
+ * `<ImportButton>` is compatible with the {@link https://refine.dev/docs/api-reference/antd/hooks/import/useImport `useImport`} hook and is meant to be used as it's upload button.
+ * It uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} and {@link https://ant.design/components/upload/ `<Upload>`} components.
+ * It wraps a `<Button>` component with an `<Upload>` component and accepts properties for `<Button>` and `<Upload>` components separately.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/import-button} for more details.
+ */
+export const ImportButton: React.FC<ImportButtonProps> = ({
+    uploadProps,
+    buttonProps,
+    hideText = false,
+    children,
+}) => {
+    const translate = useTranslate();
+
+    return (
+        <Upload {...uploadProps}>
+            <Button
+                icon={<ImportOutlined />}
+                data-testid={RefineButtonTestIds.ImportButton}
+                className={RefineButtonClassNames.ImportButton}
+                {...buttonProps}
+            >
+                {!hideText &&
+                    (children ?? translate("buttons.import", "Import"))}
+            </Button>
+        </Upload>
+    );
+};

+ 11 - 0
packages/antd/src/components/buttons/index.ts

@@ -0,0 +1,11 @@
+export { CreateButton } from "./create";
+export { EditButton } from "./edit";
+export { DeleteButton } from "./delete";
+export { RefreshButton } from "./refresh";
+export { ShowButton } from "./show";
+export { ListButton } from "./list";
+export { ExportButton } from "./export";
+export { SaveButton } from "./save";
+export { CloneButton } from "./clone";
+export { ImportButton } from "./import";
+export * from "./types";

+ 6 - 0
packages/antd/src/components/buttons/list/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonListTests } from "@refinedev/ui-tests";
+import { ListButton } from "./";
+
+describe("List Button", () => {
+    buttonListTests.bind(this)(ListButton);
+});

+ 136 - 0
packages/antd/src/components/buttons/list/index.tsx

@@ -0,0 +1,136 @@
+import React, { useContext } from "react";
+import { Button } from "antd";
+import { BarsOutlined } from "@ant-design/icons";
+import {
+    useCan,
+    useNavigation,
+    useTranslate,
+    useUserFriendlyName,
+    useResource,
+    useRouterContext,
+    useRouterType,
+    useLink,
+    pickNotDeprecated,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { ListButtonProps } from "../types";
+
+/**
+ * `<ListButton>` is using Ant Design's {@link https://ant.design/components/button/ `<Button>`} component.
+ * It uses the  {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#list `list`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation `useNavigation`} under the hood.
+ * It can be useful when redirecting the app to the list page route of resource}.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/list-button} for more details.
+ */
+export const ListButton: React.FC<ListButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    hideText = false,
+    accessControl,
+    meta,
+    children,
+    onClick,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const { listUrl: generateListUrl } = useNavigation();
+    const routerType = useRouterType();
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+    const getUserFriendlyName = useUserFriendlyName();
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    const translate = useTranslate();
+
+    const { resource, identifier } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "list",
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+        params: {
+            resource,
+        },
+    });
+
+    const createButtonDisabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const listUrl = resource ? generateListUrl(resource, meta) : "";
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <ActiveLink
+            to={listUrl}
+            replace={false}
+            onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
+                if (data?.can === false) {
+                    e.preventDefault();
+                    return;
+                }
+                if (onClick) {
+                    e.preventDefault();
+                    onClick(e);
+                }
+            }}
+        >
+            <Button
+                icon={<BarsOutlined />}
+                disabled={data?.can === false}
+                title={createButtonDisabledTitle()}
+                data-testid={RefineButtonTestIds.ListButton}
+                className={RefineButtonClassNames.ListButton}
+                {...rest}
+            >
+                {!hideText &&
+                    (children ??
+                        translate(
+                            `${
+                                identifier ??
+                                resourceNameFromProps ??
+                                propResourceNameOrRouteName
+                            }.titles.list`,
+                            getUserFriendlyName(
+                                resource?.meta?.label ??
+                                    resource?.label ??
+                                    identifier ??
+                                    pickNotDeprecated(
+                                        resourceNameFromProps,
+                                        propResourceNameOrRouteName,
+                                    ),
+                                "plural",
+                            ),
+                        ))}
+            </Button>
+        </ActiveLink>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/refresh/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonRefreshTests } from "@refinedev/ui-tests";
+import { RefreshButton } from "./";
+
+describe("Refresh Button", () => {
+    buttonRefreshTests.bind(this)(RefreshButton);
+});

+ 76 - 0
packages/antd/src/components/buttons/refresh/index.tsx

@@ -0,0 +1,76 @@
+import React from "react";
+import { Button } from "antd";
+import { RedoOutlined } from "@ant-design/icons";
+import {
+    useTranslate,
+    useResource,
+    useInvalidate,
+    queryKeys,
+    pickDataProvider,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { RefreshButtonProps } from "../types";
+
+import { useQueryClient } from "@tanstack/react-query";
+
+/**
+ * `<RefreshButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} component
+ * to update the data shown on the page via the {@link https://refine.dev/docs/api-reference/core/hooks/invalidate/useInvalidate `useInvalidate`} hook.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/refresh-button} for more details.
+ */
+export const RefreshButton: React.FC<RefreshButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    recordItemId,
+    hideText = false,
+    dataProviderName,
+    children,
+    onClick,
+    meta: _meta,
+    metaData: _metaData,
+    ...rest
+}) => {
+    const translate = useTranslate();
+
+    const queryClient = useQueryClient();
+    const invalidates = useInvalidate();
+
+    const { resources, identifier, id } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const isInvalidating = !!queryClient.isFetching({
+        queryKey: queryKeys(
+            identifier,
+            pickDataProvider(identifier, dataProviderName, resources),
+        ).detail(recordItemId ?? id),
+    });
+
+    const handleInvalidate = () => {
+        invalidates({
+            id: recordItemId ?? id,
+            invalidates: ["detail"],
+            dataProviderName,
+            resource: identifier,
+        });
+    };
+
+    return (
+        <Button
+            onClick={(e) => {
+                onClick ? onClick(e) : handleInvalidate();
+            }}
+            icon={<RedoOutlined spin={isInvalidating} />}
+            data-testid={RefineButtonTestIds.RefreshButton}
+            className={RefineButtonClassNames.RefreshButton}
+            {...rest}
+        >
+            {!hideText && (children ?? translate("buttons.refresh", "Refresh"))}
+        </Button>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/save/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonSaveTests } from "@refinedev/ui-tests";
+import { SaveButton } from "./";
+
+describe("Save Button", () => {
+    buttonSaveTests.bind(this)(SaveButton);
+});

+ 36 - 0
packages/antd/src/components/buttons/save/index.tsx

@@ -0,0 +1,36 @@
+import React from "react";
+import { Button } from "antd";
+import { SaveOutlined } from "@ant-design/icons";
+import { useTranslate } from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { SaveButtonProps } from "../types";
+
+/**
+ * `<SaveButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} component.
+ * It uses it for presantation purposes only. Some of the hooks that refine has adds features to this button.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/save-button} for more details.
+ */
+export const SaveButton: React.FC<SaveButtonProps> = ({
+    hideText = false,
+    children,
+    ...rest
+}) => {
+    const translate = useTranslate();
+
+    return (
+        <Button
+            type="primary"
+            icon={<SaveOutlined />}
+            data-testid={RefineButtonTestIds.SaveButton}
+            className={RefineButtonClassNames.SaveButton}
+            {...rest}
+        >
+            {!hideText && (children ?? translate("buttons.save", "Save"))}
+        </Button>
+    );
+};

+ 6 - 0
packages/antd/src/components/buttons/show/index.spec.tsx

@@ -0,0 +1,6 @@
+import { buttonShowTests } from "@refinedev/ui-tests";
+import { ShowButton } from "./";
+
+describe("Show Button", () => {
+    buttonShowTests.bind(this)(ShowButton);
+});

+ 117 - 0
packages/antd/src/components/buttons/show/index.tsx

@@ -0,0 +1,117 @@
+import React, { useContext } from "react";
+import { Button } from "antd";
+import { EyeOutlined } from "@ant-design/icons";
+import {
+    useCan,
+    useNavigation,
+    useTranslate,
+    useResource,
+    useRouterContext,
+    useRouterType,
+    useLink,
+    AccessControlContext,
+} from "@refinedev/core";
+import {
+    RefineButtonClassNames,
+    RefineButtonTestIds,
+} from "@refinedev/ui-types";
+
+import { ShowButtonProps } from "../types";
+
+/**
+ * `<ShowButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button>`} component.
+ * It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#show `show`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation `useNavigation`} under the hood.
+ * It can be useful when redirecting the app to the show page with the record id route of resource.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/show-button} for more details.
+ */
+export const ShowButton: React.FC<ShowButtonProps> = ({
+    resource: resourceNameFromProps,
+    resourceNameOrRouteName: propResourceNameOrRouteName,
+    recordItemId,
+    hideText = false,
+    accessControl,
+    meta,
+    children,
+    onClick,
+    ...rest
+}) => {
+    const accessControlContext = useContext(AccessControlContext);
+
+    const accessControlEnabled =
+        accessControl?.enabled ??
+        accessControlContext.options.buttons.enableAccessControl;
+
+    const hideIfUnauthorized =
+        accessControl?.hideIfUnauthorized ??
+        accessControlContext.options.buttons.hideIfUnauthorized;
+
+    const { showUrl: generateShowUrl } = useNavigation();
+    const routerType = useRouterType();
+    const Link = useLink();
+    const { Link: LegacyLink } = useRouterContext();
+
+    const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
+
+    const translate = useTranslate();
+
+    const { id, resource } = useResource(
+        resourceNameFromProps ?? propResourceNameOrRouteName,
+    );
+
+    const { data } = useCan({
+        resource: resource?.name,
+        action: "show",
+        params: { id: recordItemId ?? id, resource },
+        queryOptions: {
+            enabled: accessControlEnabled,
+        },
+    });
+
+    const createButtonDisabledTitle = () => {
+        if (data?.can) return "";
+        else if (data?.reason) return data.reason;
+        else
+            return translate(
+                "buttons.notAccessTitle",
+                "You don't have permission to access",
+            );
+    };
+
+    const showUrl =
+        resource && (recordItemId || id)
+            ? generateShowUrl(resource, recordItemId! ?? id!, meta)
+            : "";
+
+    if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
+        return null;
+    }
+
+    return (
+        <ActiveLink
+            to={showUrl}
+            replace={false}
+            onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
+                if (data?.can === false) {
+                    e.preventDefault();
+                    return;
+                }
+                if (onClick) {
+                    e.preventDefault();
+                    onClick(e);
+                }
+            }}
+        >
+            <Button
+                icon={<EyeOutlined />}
+                disabled={data?.can === false}
+                title={createButtonDisabledTitle()}
+                data-testid={RefineButtonTestIds.ShowButton}
+                className={RefineButtonClassNames.ShowButton}
+                {...rest}
+            >
+                {!hideText && (children ?? translate("buttons.show", "Show"))}
+            </Button>
+        </ActiveLink>
+    );
+};

+ 44 - 0
packages/antd/src/components/buttons/types.ts

@@ -0,0 +1,44 @@
+import { ButtonProps, UploadProps } from "antd";
+import {
+    RefineCloneButtonProps,
+    RefineCreateButtonProps,
+    RefineDeleteButtonProps,
+    RefineEditButtonProps,
+    RefineExportButtonProps,
+    RefineImportButtonProps,
+    RefineListButtonProps,
+    RefineRefreshButtonProps,
+    RefineSaveButtonProps,
+    RefineShowButtonProps,
+} from "@refinedev/ui-types";
+
+export type ShowButtonProps = RefineShowButtonProps<ButtonProps>;
+
+export type CloneButtonProps = RefineCloneButtonProps<ButtonProps>;
+
+export type CreateButtonProps = RefineCreateButtonProps<ButtonProps>;
+
+export type DeleteButtonProps = RefineDeleteButtonProps<ButtonProps>;
+
+export type EditButtonProps = RefineEditButtonProps<ButtonProps>;
+
+export type ExportButtonProps = RefineExportButtonProps<ButtonProps>;
+
+export type ImportButtonProps = RefineImportButtonProps & {
+    /**
+     * Sets the button type
+     * @type [UploadProps](https://ant.design/components/upload/#API)
+     */
+    uploadProps: UploadProps;
+    /**
+     * Sets props of the button
+     * @type [ButtonProps](https://ant.design/components/button/#API)
+     */
+    buttonProps: ButtonProps;
+};
+
+export type ListButtonProps = RefineListButtonProps<ButtonProps>;
+
+export type RefreshButtonProps = RefineRefreshButtonProps<ButtonProps>;
+
+export type SaveButtonProps = RefineSaveButtonProps<ButtonProps>;

+ 45 - 0
packages/antd/src/components/crud/create/index.spec.tsx

@@ -0,0 +1,45 @@
+import React, { ReactNode } from "react";
+import { Route, Routes } from "react-router-dom";
+import { crudCreateTests } from "@refinedev/ui-tests";
+import { render, TestWrapper } from "@test";
+import { Create } from "./";
+import { SaveButton } from "@components/buttons";
+import { RefineButtonTestIds } from "@refinedev/ui-types";
+
+const renderCreate = (create: ReactNode) => {
+    return render(
+        <Routes>
+            <Route path="/:resource/create" element={create} />
+        </Routes>,
+        {
+            wrapper: TestWrapper({
+                routerInitialEntries: ["/posts/create"],
+            }),
+        },
+    );
+};
+
+describe("Create", () => {
+    crudCreateTests.bind(this)(Create);
+
+    it("should customize default buttons with default props", async () => {
+        const { queryByTestId } = renderCreate(
+            <Create
+                saveButtonProps={{ className: "customize-test" }}
+                footerButtons={({ saveButtonProps }) => {
+                    expect(saveButtonProps).toBeDefined();
+
+                    return (
+                        <>
+                            <SaveButton {...saveButtonProps} />
+                        </>
+                    );
+                }}
+            />,
+        );
+
+        expect(queryByTestId(RefineButtonTestIds.SaveButton)).toHaveClass(
+            "customize-test",
+        );
+    });
+});

+ 144 - 0
packages/antd/src/components/crud/create/index.tsx

@@ -0,0 +1,144 @@
+import React from "react";
+import { Card, Space, Spin } from "antd";
+import {
+    useNavigation,
+    useTranslate,
+    useUserFriendlyName,
+    useRefineContext,
+    useRouterType,
+    useResource,
+    useBack,
+} from "@refinedev/core";
+
+import {
+    Breadcrumb,
+    SaveButton,
+    PageHeader,
+    SaveButtonProps,
+} from "@components";
+import { CreateProps } from "../types";
+
+/**
+ * `<Create>` provides us a layout to display the page.
+ * It does not contain any logic but adds extra functionalities like action buttons and giving titles to the page.
+ *
+ * @see {@link https://refine.dev/docs/ui-frameworks/antd/components/basic-views/create} for more details.
+ */
+export const Create: React.FC<CreateProps> = ({
+    title,
+    saveButtonProps: saveButtonPropsFromProps,
+    children,
+    resource: resourceFromProps,
+    isLoading = false,
+    breadcrumb: breadcrumbFromProps,
+    wrapperProps,
+    headerProps,
+    contentProps,
+    headerButtonProps,
+    headerButtons,
+    footerButtonProps,
+    footerButtons,
+    goBack: goBackFromProps,
+}) => {
+    const translate = useTranslate();
+    const { options: { breadcrumb: globalBreadcrumb } = {} } =
+        useRefineContext();
+
+    const routerType = useRouterType();
+    const back = useBack();
+    const { goBack } = useNavigation();
+    const getUserFriendlyName = useUserFriendlyName();
+
+    const { resource, action, identifier } = useResource(resourceFromProps);
+
+    const breadcrumb =
+        typeof breadcrumbFromProps === "undefined"
+            ? globalBreadcrumb
+            : breadcrumbFromProps;
+
+    const saveButtonProps: SaveButtonProps = {
+        ...(isLoading ? { disabled: true } : {}),
+        ...saveButtonPropsFromProps,
+        htmlType: "submit",
+    };
+
+    const defaultFooterButtons = (
+        <>
+            <SaveButton {...saveButtonProps} />
+        </>
+    );
+
+    return (
+        <div {...(wrapperProps ?? {})}>
+            <PageHeader
+                ghost={false}
+                backIcon={goBackFromProps}
+                onBack={
+                    action !== "list" || typeof action !== "undefined"
+                        ? routerType === "legacy"
+                            ? goBack
+                            : back
+                        : undefined
+                }
+                title={
+                    title ??
+                    translate(
+                        `${identifier}.titles.create`,
+                        `Create ${getUserFriendlyName(
+                            resource?.meta?.label ??
+                                resource?.options?.label ??
+                                resource?.label ??
+                                identifier,
+                            "singular",
+                        )}`,
+                    )
+                }
+                breadcrumb={
+                    typeof breadcrumb !== "undefined" ? (
+                        <>{breadcrumb}</> ?? undefined
+                    ) : (
+                        <Breadcrumb />
+                    )
+                }
+                extra={
+                    <Space wrap {...(headerButtonProps ?? {})}>
+                        {headerButtons
+                            ? typeof headerButtons === "function"
+                                ? headerButtons({
+                                      defaultButtons: null,
+                                  })
+                                : headerButtons
+                            : null}
+                    </Space>
+                }
+                {...(headerProps ?? {})}
+            >
+                <Spin spinning={isLoading}>
+                    <Card
+                        bordered={false}
+                        actions={[
+                            <Space
+                                key="action-buttons"
+                                style={{ float: "right", marginRight: 24 }}
+                                {...(footerButtonProps ?? {})}
+                            >
+                                {footerButtons
+                                    ? typeof footerButtons === "function"
+                                        ? footerButtons({
+                                              defaultButtons:
+                                                  defaultFooterButtons,
+                                              saveButtonProps: saveButtonProps,
+                                          })
+                                        : footerButtons
+                                    : defaultFooterButtons}
+                            </Space>,
+                        ]}
+                        {...(contentProps ?? {})}
+                    >
+                        {children}
+                    </Card>
+                </Spin>
+            </PageHeader>
+        </div>
+    );
+};

+ 521 - 0
packages/antd/src/components/crud/edit/index.spec.tsx

@@ -0,0 +1,521 @@
+import React, { ReactNode } from "react";
+import { Route, Routes } from "react-router-dom";
+import { AccessControlProvider } from "@refinedev/core";
+import { Form, Input } from "antd";
+
+import {
+    act,
+    fireEvent,
+    ITestWrapperProps,
+    render,
+    TestWrapper,
+    waitFor,
+    MockJSONServer,
+} from "@test";
+import { Edit } from "./";
+import { crudEditTests } from "@refinedev/ui-tests";
+import { RefineButtonTestIds } from "@refinedev/ui-types";
+import {
+    DeleteButton,
+    ListButton,
+    RefreshButton,
+    SaveButton,
+} from "@components/buttons";
+import { useForm } from "@hooks/form";
+
+const renderEdit = (
+    edit: ReactNode,
+    accessControlProvider?: AccessControlProvider,
+    wrapperOptions?: ITestWrapperProps,
+) => {
+    return render(
+        <Routes>
+            <Route path="/:resource/edit/:id" element={edit} />
+        </Routes>,
+        {
+            wrapper: TestWrapper({
+                routerInitialEntries: ["/posts/edit/1"],
+                accessControlProvider,
+                ...wrapperOptions,
+            }),
+        },
+    );
+};
+
+describe("Edit", () => {
+    crudEditTests.bind(this)(Edit);
+
+    it("should render optional mutationMode with mutationModeProp prop", async () => {
+        const container = renderEdit(<Edit mutationMode="undoable" />);
+
+        expect(container).toBeTruthy();
+    });
+
+    describe("render delete button", () => {
+        it("should render delete button ", async () => {
+            const { getByText, queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={
+                            <Edit
+                                footerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: true }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+
+            getByText("Edit Post");
+        });
+
+        it("should not render delete button on resource canDelete false", async () => {
+            const { getByText, queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={
+                            <Edit
+                                footerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeUndefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.DeleteButton)).toBeNull();
+
+            getByText("Edit Post");
+        });
+
+        it("should not render delete button on resource canDelete true & canDelete props false on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={
+                            <Edit
+                                canDelete={false}
+                                footerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeUndefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    ></Route>
+                </Routes>,
+
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: true }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.DeleteButton)).toBeNull();
+        });
+
+        it("should render delete button on resource canDelete false & canDelete props true on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={
+                            <Edit
+                                canDelete={true}
+                                footerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+        });
+
+        it("should render delete button on resource canDelete false & deleteButtonProps props not null on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={
+                            <Edit
+                                deleteButtonProps={{ size: "large" }}
+                                footerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+        });
+    });
+
+    describe("accessibility of buttons by accessControlProvider", () => {
+        it("should render disabled list button and not disabled delete button", async () => {
+            const { queryByTestId } = renderEdit(
+                <Edit
+                    canDelete
+                    footerButtons={({ defaultButtons, deleteButtonProps }) => {
+                        expect(deleteButtonProps).toBeDefined();
+                        return <>{defaultButtons}</>;
+                    }}
+                />,
+                {
+                    can: ({ action }) => {
+                        switch (action) {
+                            case "list":
+                                return Promise.resolve({ can: true });
+                            case "delete":
+                            default:
+                                return Promise.resolve({ can: false });
+                        }
+                    },
+                },
+            );
+
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).not.toBeDisabled(),
+            );
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.DeleteButton),
+                ).toBeDisabled(),
+            );
+        });
+
+        it("should render disabled list button and delete button", async () => {
+            const { queryByTestId } = renderEdit(
+                <Edit
+                    canDelete
+                    headerButtons={({ defaultButtons, listButtonProps }) => {
+                        expect(listButtonProps).toBeDefined();
+                        return <>{defaultButtons}</>;
+                    }}
+                    footerButtons={({ defaultButtons, deleteButtonProps }) => {
+                        expect(deleteButtonProps).toBeDefined();
+                        return <>{defaultButtons}</>;
+                    }}
+                />,
+                {
+                    can: ({ action }) => {
+                        switch (action) {
+                            case "list":
+                            case "delete":
+                                return Promise.resolve({ can: false });
+                            default:
+                                return Promise.resolve({ can: false });
+                        }
+                    },
+                },
+            );
+
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).toBeDisabled(),
+            );
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.DeleteButton),
+                ).toBeDisabled(),
+            );
+        });
+
+        it("should customize default buttons with default props", async () => {
+            const { queryByTestId } = renderEdit(
+                <Edit
+                    canDelete
+                    saveButtonProps={{ className: "customize-test" }}
+                    headerButtons={({
+                        listButtonProps,
+                        refreshButtonProps,
+                    }) => {
+                        return (
+                            <>
+                                <RefreshButton {...refreshButtonProps} />
+                                <ListButton {...listButtonProps} />
+                            </>
+                        );
+                    }}
+                    footerButtons={({ deleteButtonProps, saveButtonProps }) => {
+                        return (
+                            <>
+                                <DeleteButton {...deleteButtonProps} />
+                                <SaveButton {...saveButtonProps} />
+                            </>
+                        );
+                    }}
+                />,
+                {
+                    can: ({ action }) => {
+                        switch (action) {
+                            case "list":
+                            case "delete":
+                                return Promise.resolve({ can: false });
+                            default:
+                                return Promise.resolve({ can: false });
+                        }
+                    },
+                },
+            );
+
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.DeleteButton),
+                ).toBeDisabled(),
+            );
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).toBeDisabled(),
+            );
+            expect(queryByTestId(RefineButtonTestIds.SaveButton)).toHaveClass(
+                "customize-test",
+            );
+            expect(
+                queryByTestId(RefineButtonTestIds.RefreshButton),
+            ).toBeTruthy();
+        });
+    });
+
+    describe("list button", () => {
+        it("should render list button", async () => {
+            const { queryByTestId } = renderEdit(<Edit />);
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).not.toBeNull(),
+            );
+        });
+
+        it("should not render list button when list resource is undefined", async () => {
+            const { queryByTestId } = renderEdit(
+                <Edit
+                    headerButtons={({ defaultButtons, listButtonProps }) => {
+                        expect(listButtonProps).toBeUndefined();
+                        return <>{defaultButtons}</>;
+                    }}
+                />,
+                undefined,
+                {
+                    resources: [{ name: "posts", list: undefined }],
+                },
+            );
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).toBeNull(),
+            );
+        });
+
+        it("should not render list button when has recordItemId", async () => {
+            const { queryByTestId } = renderEdit(
+                <Edit
+                    recordItemId="1"
+                    headerButtons={({ defaultButtons, listButtonProps }) => {
+                        expect(listButtonProps).toBeUndefined();
+                        return <>{defaultButtons}</>;
+                    }}
+                />,
+            );
+            await waitFor(() =>
+                expect(
+                    queryByTestId(RefineButtonTestIds.ListButton),
+                ).toBeNull(),
+            );
+        });
+    });
+
+    describe("auto save", () => {
+        const EditPageWithAutoSave = () => {
+            const { formProps, formLoading, autoSaveProps } = useForm({
+                action: "edit",
+                autoSave: {
+                    enabled: true,
+                },
+            });
+
+            return (
+                <Edit autoSaveProps={autoSaveProps}>
+                    {formLoading && <div>loading...</div>}
+                    <Form {...formProps} layout="vertical">
+                        <Form.Item label="Title" name="title">
+                            <Input data-testid="title" />
+                        </Form.Item>
+                    </Form>
+                </Edit>
+            );
+        };
+
+        it("check idle,loading,success statuses", async () => {
+            jest.useFakeTimers();
+
+            const { getByText, getByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={<EditPageWithAutoSave />}
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                        dataProvider: {
+                            ...MockJSONServer,
+                            update: () => {
+                                return new Promise((res) => {
+                                    setTimeout(
+                                        () =>
+                                            res({
+                                                data: {
+                                                    id: "1",
+                                                    title: "ok",
+                                                } as any,
+                                            }),
+                                        1000,
+                                    );
+                                });
+                            },
+                        },
+                    }),
+                },
+            );
+
+            getByText("Edit Post");
+            getByText("waiting for changes");
+
+            // update title and wait
+            await act(async () => {
+                fireEvent.change(getByTestId("title"), {
+                    target: { value: "test" },
+                });
+
+                jest.advanceTimersByTime(1100);
+            });
+
+            // check saving message
+            expect(getByText("saving...")).toBeTruthy();
+
+            await act(async () => {
+                jest.advanceTimersByTime(1000);
+            });
+
+            // check saved message
+            expect(getByText("saved")).toBeTruthy();
+        });
+
+        it("check error status", async () => {
+            jest.useFakeTimers();
+
+            const { getByText, getByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/edit/:id"
+                        element={<EditPageWithAutoSave />}
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/edit/1"],
+                        dataProvider: {
+                            ...MockJSONServer,
+                            update: () => {
+                                return new Promise((res, rej) => {
+                                    setTimeout(() => rej("error"), 1000);
+                                });
+                            },
+                        },
+                    }),
+                },
+            );
+
+            getByText("Edit Post");
+            getByText("waiting for changes");
+
+            // update title and wait
+            await act(async () => {
+                fireEvent.change(getByTestId("title"), {
+                    target: { value: "test" },
+                });
+
+                jest.advanceTimersByTime(1100);
+            });
+
+            // check saving message
+            expect(getByText("saving...")).toBeTruthy();
+
+            await act(async () => {
+                jest.advanceTimersByTime(1000);
+            });
+
+            // check saved message
+            expect(getByText("auto save failure")).toBeTruthy();
+        });
+    });
+});

+ 231 - 0
packages/antd/src/components/crud/edit/index.tsx

@@ -0,0 +1,231 @@
+import React from "react";
+
+import { Card, Space, Spin } from "antd";
+import {
+    useMutationMode,
+    useNavigation,
+    useTranslate,
+    useUserFriendlyName,
+    useRefineContext,
+    useRouterType,
+    useBack,
+    useResource,
+    useGo,
+    useToPath,
+} from "@refinedev/core";
+
+import {
+    DeleteButton,
+    RefreshButton,
+    ListButton,
+    SaveButton,
+    Breadcrumb,
+    PageHeader,
+    ListButtonProps,
+    RefreshButtonProps,
+    DeleteButtonProps,
+    SaveButtonProps,
+    AutoSaveIndicator,
+} from "@components";
+import { EditProps } from "../types";
+
+/**
+ * `<Edit>` provides us a layout for displaying the page.
+ * It does not contain any logic but adds extra functionalities like a refresh button.
+ *
+ * @see {@link https://refine.dev/docs/ui-frameworks/antd/components/basic-views/edit} for more details.
+ */
+export const Edit: React.FC<EditProps> = ({
+    title,
+    saveButtonProps: saveButtonPropsFromProps,
+    mutationMode: mutationModeProp,
+    recordItemId,
+    children,
+    deleteButtonProps: deleteButtonPropsFromProps,
+    canDelete,
+    resource: resourceFromProps,
+    isLoading = false,
+    dataProviderName,
+    breadcrumb: breadcrumbFromProps,
+    wrapperProps,
+    headerProps,
+    contentProps,
+    headerButtonProps,
+    headerButtons,
+    footerButtonProps,
+    footerButtons,
+    goBack: goBackFromProps,
+    autoSaveProps,
+}) => {
+    const translate = useTranslate();
+    const { options: { breadcrumb: globalBreadcrumb } = {} } =
+        useRefineContext();
+    const { mutationMode: mutationModeContext } = useMutationMode();
+    const mutationMode = mutationModeProp ?? mutationModeContext;
+
+    const routerType = useRouterType();
+    const back = useBack();
+    const go = useGo();
+    const { goBack, list: legacyGoList } = useNavigation();
+    const getUserFriendlyName = useUserFriendlyName();
+
+    const {
+        resource,
+        action,
+        id: idFromParams,
+        identifier,
+    } = useResource(resourceFromProps);
+
+    const goListPath = useToPath({
+        resource,
+        action: "list",
+    });
+
+    const id = recordItemId ?? idFromParams;
+
+    const breadcrumb =
+        typeof breadcrumbFromProps === "undefined"
+            ? globalBreadcrumb
+            : breadcrumbFromProps;
+
+    const hasList = resource?.list && !recordItemId;
+    const isDeleteButtonVisible =
+        canDelete ??
+        ((resource?.meta?.canDelete ?? resource?.canDelete) ||
+            deleteButtonPropsFromProps);
+
+    const listButtonProps: ListButtonProps | undefined = hasList
+        ? {
+              ...(isLoading ? { disabled: true } : {}),
+              resource: routerType === "legacy" ? resource?.route : identifier,
+          }
+        : undefined;
+
+    const refreshButtonProps: RefreshButtonProps = {
+        ...(isLoading ? { disabled: true } : {}),
+        resource: routerType === "legacy" ? resource?.route : identifier,
+        recordItemId: id,
+        dataProviderName,
+    };
+
+    const deleteButtonProps: DeleteButtonProps | undefined =
+        isDeleteButtonVisible
+            ? {
+                  ...(isLoading ? { disabled: true } : {}),
+                  resource:
+                      routerType === "legacy" ? resource?.route : identifier,
+                  mutationMode,
+                  onSuccess: () => {
+                      if (routerType === "legacy") {
+                          legacyGoList(resource?.route ?? resource?.name ?? "");
+                      } else {
+                          go({ to: goListPath });
+                      }
+                  },
+                  recordItemId: id,
+                  dataProviderName,
+                  ...deleteButtonPropsFromProps,
+              }
+            : undefined;
+
+    const saveButtonProps: SaveButtonProps = {
+        ...(isLoading ? { disabled: true } : {}),
+        ...saveButtonPropsFromProps,
+    };
+
+    const defaultHeaderButtons = (
+        <>
+            {autoSaveProps && <AutoSaveIndicator {...autoSaveProps} />}
+            {hasList && <ListButton {...listButtonProps} />}
+            <RefreshButton {...refreshButtonProps} />
+        </>
+    );
+
+    const defaultFooterButtons = (
+        <>
+            {isDeleteButtonVisible && <DeleteButton {...deleteButtonProps} />}
+            <SaveButton {...saveButtonProps} />
+        </>
+    );
+
+    return (
+        <div {...(wrapperProps ?? {})}>
+            <PageHeader
+                ghost={false}
+                backIcon={goBackFromProps}
+                onBack={
+                    action !== "list" && typeof action !== "undefined"
+                        ? routerType === "legacy"
+                            ? goBack
+                            : back
+                        : undefined
+                }
+                title={
+                    title ??
+                    translate(
+                        `${identifier}.titles.edit`,
+                        `Edit ${getUserFriendlyName(
+                            resource?.meta?.label ??
+                                resource?.options?.label ??
+                                resource?.label ??
+                                identifier,
+                            "singular",
+                        )}`,
+                    )
+                }
+                extra={
+                    <Space wrap {...(headerButtonProps ?? {})}>
+                        {headerButtons
+                            ? typeof headerButtons === "function"
+                                ? headerButtons({
+                                      defaultButtons: defaultHeaderButtons,
+                                      listButtonProps,
+                                      refreshButtonProps,
+                                  })
+                                : headerButtons
+                            : defaultHeaderButtons}
+                    </Space>
+                }
+                breadcrumb={
+                    typeof breadcrumb !== "undefined" ? (
+                        <>{breadcrumb}</> ?? undefined
+                    ) : (
+                        <Breadcrumb />
+                    )
+                }
+                {...(headerProps ?? {})}
+            >
+                <Spin spinning={isLoading}>
+                    <Card
+                        bordered={false}
+                        actions={[
+                            <Space
+                                key="footer-buttons"
+                                wrap
+                                style={{
+                                    float: "right",
+                                    marginRight: 24,
+                                }}
+                                {...(footerButtonProps ?? {})}
+                            >
+                                {footerButtons
+                                    ? typeof footerButtons === "function"
+                                        ? footerButtons({
+                                              defaultButtons:
+                                                  defaultFooterButtons,
+                                              deleteButtonProps,
+                                              saveButtonProps,
+                                          })
+                                        : footerButtons
+                                    : defaultFooterButtons}
+                            </Space>,
+                        ]}
+                        {...(contentProps ?? {})}
+                    >
+                        {children}
+                    </Card>
+                </Spin>
+            </PageHeader>
+        </div>
+    );
+};

+ 6 - 0
packages/antd/src/components/crud/index.ts

@@ -0,0 +1,6 @@
+export { List } from "./list";
+export { Create } from "./create";
+export { Edit } from "./edit";
+export { Show } from "./show";
+
+export * from "./types";

+ 45 - 0
packages/antd/src/components/crud/list/index.spec.tsx

@@ -0,0 +1,45 @@
+import React, { ReactNode } from "react";
+import { crudListTests } from "@refinedev/ui-tests";
+import { RefineButtonTestIds } from "@refinedev/ui-types";
+import { Route, Routes } from "react-router-dom";
+import { CreateButton } from "@components/buttons";
+import { render, TestWrapper } from "@test";
+import { List } from "./index";
+
+const renderList = (list: ReactNode) => {
+    return render(
+        <Routes>
+            <Route path="/:resource" element={list} />
+        </Routes>,
+        {
+            wrapper: TestWrapper({
+                routerInitialEntries: ["/posts"],
+            }),
+        },
+    );
+};
+
+describe("<List/>", () => {
+    crudListTests.bind(this)(List);
+
+    it("should customize default buttons with default props", async () => {
+        const { queryByTestId } = renderList(
+            <List
+                createButtonProps={{ className: "customize-test" }}
+                headerButtons={({ createButtonProps }) => {
+                    expect(createButtonProps).toBeDefined();
+
+                    return (
+                        <>
+                            <CreateButton {...createButtonProps} />
+                        </>
+                    );
+                }}
+            />,
+        );
+
+        expect(queryByTestId(RefineButtonTestIds.CreateButton)).toHaveClass(
+            "customize-test",
+        );
+    });
+});

+ 115 - 0
packages/antd/src/components/crud/list/index.tsx

@@ -0,0 +1,115 @@
+import React from "react";
+import { Space } from "antd";
+import {
+    useTranslate,
+    useUserFriendlyName,
+    useRefineContext,
+    useRouterType,
+    useResource,
+} from "@refinedev/core";
+
+import {
+    Breadcrumb,
+    CreateButton,
+    CreateButtonProps,
+    PageHeader,
+} from "@components";
+import { ListProps } from "../types";
+
+/**
+ * `<List>` provides us a layout for displaying the page.
+ * It does not contain any logic but adds extra functionalities like a refresh button.
+ *
+ * @see {@link https://refine.dev/docs/ui-frameworks/antd/components/basic-views/list} for more details.
+ */
+export const List: React.FC<ListProps> = ({
+    canCreate,
+    title,
+    children,
+    createButtonProps: createButtonPropsFromProps,
+    resource: resourceFromProps,
+    wrapperProps,
+    contentProps,
+    headerProps,
+    breadcrumb: breadcrumbFromProps,
+    headerButtonProps,
+    headerButtons,
+}) => {
+    const translate = useTranslate();
+    const { options: { breadcrumb: globalBreadcrumb } = {} } =
+        useRefineContext();
+
+    const routerType = useRouterType();
+    const getUserFriendlyName = useUserFriendlyName();
+
+    const { resource, identifier } = useResource(resourceFromProps);
+
+    const isCreateButtonVisible =
+        canCreate ??
+        ((resource?.canCreate ?? !!resource?.create) ||
+            createButtonPropsFromProps);
+
+    const breadcrumb =
+        typeof breadcrumbFromProps === "undefined"
+            ? globalBreadcrumb
+            : breadcrumbFromProps;
+
+    const createButtonProps: CreateButtonProps | undefined =
+        isCreateButtonVisible
+            ? {
+                  size: "middle",
+                  resource:
+                      routerType === "legacy" ? resource?.route : identifier,
+                  ...createButtonPropsFromProps,
+              }
+            : undefined;
+
+    const defaultExtra = isCreateButtonVisible ? (
+        <CreateButton {...createButtonProps} />
+    ) : null;
+
+    return (
+        <div {...(wrapperProps ?? {})}>
+            <PageHeader
+                ghost={false}
+                title={
+                    title ??
+                    translate(
+                        `${identifier}.titles.list`,
+                        getUserFriendlyName(
+                            resource?.meta?.label ??
+                                resource?.options?.label ??
+                                resource?.label ??
+                                identifier,
+                            "plural",
+                        ),
+                    )
+                }
+                extra={
+                    headerButtons ? (
+                        <Space wrap {...headerButtonProps}>
+                            {typeof headerButtons === "function"
+                                ? headerButtons({
+                                      defaultButtons: defaultExtra,
+                                      createButtonProps,
+                                  })
+                                : headerButtons}
+                        </Space>
+                    ) : (
+                        defaultExtra
+                    )
+                }
+                breadcrumb={
+                    typeof breadcrumb !== "undefined" ? (
+                        <>{breadcrumb}</> ?? undefined
+                    ) : (
+                        <Breadcrumb />
+                    )
+                }
+                {...(headerProps ?? {})}
+            >
+                <div {...(contentProps ?? {})}>{children}</div>
+            </PageHeader>
+        </div>
+    );
+};

+ 459 - 0
packages/antd/src/components/crud/show/index.spec.tsx

@@ -0,0 +1,459 @@
+import React, { ReactNode } from "react";
+import { Route, Routes } from "react-router-dom";
+import { RefineButtonTestIds } from "@refinedev/ui-types";
+import { AccessControlProvider } from "@refinedev/core";
+
+import { render, TestWrapper, waitFor } from "@test";
+
+import { Show } from "./index";
+import { crudShowTests } from "@refinedev/ui-tests";
+import {
+    DeleteButton,
+    EditButton,
+    ListButton,
+    RefreshButton,
+} from "@components/buttons";
+
+const renderShow = (
+    show: ReactNode,
+    accessControlProvider?: AccessControlProvider,
+) => {
+    return render(
+        <Routes>
+            <Route path="/:resource/:action/:id" element={show} />
+        </Routes>,
+        {
+            wrapper: TestWrapper({
+                routerInitialEntries: ["/posts/show/1"],
+                accessControlProvider,
+            }),
+        },
+    );
+};
+describe("Show", () => {
+    crudShowTests.bind(this)(Show as any);
+
+    it("depending on the accessControlProvider it should get the buttons successfully", async () => {
+        const { getByText, getAllByText, queryByTestId } = renderShow(
+            <Show
+                canEdit
+                canDelete
+                headerButtons={({
+                    defaultButtons,
+                    deleteButtonProps,
+                    editButtonProps,
+                }) => {
+                    expect(deleteButtonProps).toBeDefined();
+                    expect(editButtonProps).toBeDefined();
+                    return <>{defaultButtons}</>;
+                }}
+            />,
+            {
+                can: ({ action }) => {
+                    switch (action) {
+                        case "edit":
+                        case "list":
+                            return Promise.resolve({ can: true });
+                        case "delete":
+                        default:
+                            return Promise.resolve({ can: false });
+                    }
+                },
+            },
+        );
+
+        await waitFor(() =>
+            expect(getByText("Edit").closest("button")).not.toBeDisabled(),
+        );
+        await waitFor(() =>
+            expect(
+                getAllByText("Posts")[1].closest("button"),
+            ).not.toBeDisabled(),
+        );
+
+        await waitFor(() =>
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).toBeDisabled(),
+        );
+    });
+
+    it("should render optional recordItemId with resource prop, not render list button", async () => {
+        const { getByText, queryByTestId } = renderShow(
+            <Show
+                recordItemId="1"
+                headerButtons={({ defaultButtons, listButtonProps }) => {
+                    expect(listButtonProps).not.toBeDefined();
+                    return <>{defaultButtons}</>;
+                }}
+            />,
+        );
+
+        getByText("Show Post");
+
+        expect(queryByTestId(RefineButtonTestIds.ListButton)).toBeNull();
+    });
+
+    describe("render edit button", () => {
+        it("should render edit button", async () => {
+            const { getByText, queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                headerButtons={({
+                                    defaultButtons,
+                                    editButtonProps,
+                                }) => {
+                                    expect(editButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    ></Route>
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", edit: () => null }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.EditButton),
+            ).not.toBeNull();
+
+            getByText("Show Post");
+        });
+
+        it("should not render edit button on resource canEdit false", async () => {
+            const { getByText, queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                headerButtons={({
+                                    defaultButtons,
+                                    editButtonProps,
+                                }) => {
+                                    expect(editButtonProps).not.toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts" }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.EditButton)).toBeNull();
+
+            getByText("Show Post");
+        });
+
+        it("should not render edit button on resource canEdit true & canEdit props false on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                canEdit={false}
+                                headerButtons={({
+                                    defaultButtons,
+                                    editButtonProps,
+                                }) => {
+                                    expect(editButtonProps).not.toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", edit: () => null }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.EditButton)).toBeNull();
+        });
+
+        it("should render edit button on resource canEdit false & canEdit props true on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                canEdit={true}
+                                headerButtons={({
+                                    defaultButtons,
+                                    editButtonProps,
+                                }) => {
+                                    expect(editButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts" }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.EditButton),
+            ).not.toBeNull();
+        });
+
+        it("should render edit button with recordItemId prop", async () => {
+            const { getByText, queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                recordItemId="1"
+                                headerButtons={({
+                                    defaultButtons,
+                                    editButtonProps,
+                                }) => {
+                                    expect(editButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", edit: () => null }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.EditButton),
+            ).not.toBeNull();
+
+            getByText("Show Post");
+        });
+    });
+
+    describe("render delete button", () => {
+        it("should render delete button", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                headerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: true }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+        });
+
+        it("should not render delete button on resource canDelete false", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                headerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).not.toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.DeleteButton)).toBeNull();
+        });
+
+        it("should not render delete button on resource canDelete true & canDelete props false on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                canDelete={false}
+                                headerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).not.toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: true }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(queryByTestId(RefineButtonTestIds.DeleteButton)).toBeNull();
+        });
+
+        it("should render delete button on resource canDelete false & canDelete props true on component", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                canDelete={true}
+                                headerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: false }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+        });
+
+        it("should render delete button with recordItemId prop", async () => {
+            const { queryByTestId } = render(
+                <Routes>
+                    <Route
+                        path="/:resource/:action/:id"
+                        element={
+                            <Show
+                                recordItemId="1"
+                                headerButtons={({
+                                    defaultButtons,
+                                    deleteButtonProps,
+                                }) => {
+                                    expect(deleteButtonProps).toBeDefined();
+                                    return <>{defaultButtons}</>;
+                                }}
+                            />
+                        }
+                    />
+                </Routes>,
+                {
+                    wrapper: TestWrapper({
+                        resources: [{ name: "posts", canDelete: true }],
+                        routerInitialEntries: ["/posts/show/1"],
+                    }),
+                },
+            );
+
+            expect(
+                queryByTestId(RefineButtonTestIds.DeleteButton),
+            ).not.toBeNull();
+        });
+    });
+
+    it("should customize default buttons with default props", async () => {
+        const { queryByTestId } = render(
+            <Routes>
+                <Route
+                    path="/:resource/:action/:id"
+                    element={
+                        <Show
+                            canEdit
+                            canDelete
+                            headerButtons={({
+                                deleteButtonProps,
+                                editButtonProps,
+                                listButtonProps,
+                                refreshButtonProps,
+                            }) => {
+                                return (
+                                    <>
+                                        <DeleteButton {...deleteButtonProps} />
+                                        <EditButton {...editButtonProps} />
+                                        <ListButton {...listButtonProps} />
+                                        <RefreshButton
+                                            {...refreshButtonProps}
+                                        />
+                                    </>
+                                );
+                            }}
+                        />
+                    }
+                />
+            </Routes>,
+            {
+                wrapper: TestWrapper({
+                    resources: [{ name: "posts" }],
+                    routerInitialEntries: ["/posts/show/1"],
+                }),
+            },
+        );
+
+        expect(queryByTestId(RefineButtonTestIds.DeleteButton)).not.toBeNull();
+        expect(queryByTestId(RefineButtonTestIds.EditButton)).not.toBeNull();
+        expect(queryByTestId(RefineButtonTestIds.ListButton)).not.toBeNull();
+        expect(queryByTestId(RefineButtonTestIds.RefreshButton)).not.toBeNull();
+    });
+});

+ 216 - 0
packages/antd/src/components/crud/show/index.tsx

@@ -0,0 +1,216 @@
+import React from "react";
+import { Card, Space, Spin } from "antd";
+import {
+    useNavigation,
+    useTranslate,
+    useUserFriendlyName,
+    useRefineContext,
+    useResource,
+    useToPath,
+    useRouterType,
+    useBack,
+    useGo,
+} from "@refinedev/core";
+
+import {
+    EditButton,
+    DeleteButton,
+    RefreshButton,
+    ListButton,
+    Breadcrumb,
+    PageHeader,
+    ListButtonProps,
+    EditButtonProps,
+    DeleteButtonProps,
+    RefreshButtonProps,
+} from "@components";
+import { ShowProps } from "../types";
+
+/**
+ * `<Show>` provides us a layout for displaying the page.
+ * It does not contain any logic but adds extra functionalities like a refresh button.
+ *
+ * @see {@link https://refine.dev/docs/ui-frameworks/antd/components/basic-views/show} for more details.
+ */
+export const Show: React.FC<ShowProps> = ({
+    title,
+    canEdit,
+    canDelete,
+    isLoading = false,
+    children,
+    resource: resourceFromProps,
+    recordItemId,
+    dataProviderName,
+    breadcrumb: breadcrumbFromProps,
+    contentProps,
+    headerProps,
+    wrapperProps,
+    headerButtons,
+    footerButtons,
+    footerButtonProps,
+    headerButtonProps,
+    goBack: goBackFromProps,
+}) => {
+    const translate = useTranslate();
+    const { options: { breadcrumb: globalBreadcrumb } = {} } =
+        useRefineContext();
+
+    const routerType = useRouterType();
+    const back = useBack();
+    const go = useGo();
+    const { goBack, list: legacyGoList } = useNavigation();
+    const getUserFriendlyName = useUserFriendlyName();
+
+    const {
+        resource,
+        action,
+        id: idFromParams,
+        identifier,
+    } = useResource(resourceFromProps);
+
+    const goListPath = useToPath({
+        resource,
+        action: "list",
+    });
+
+    const id = recordItemId ?? idFromParams;
+
+    const breadcrumb =
+        typeof breadcrumbFromProps === "undefined"
+            ? globalBreadcrumb
+            : breadcrumbFromProps;
+
+    const hasList = resource?.list && !recordItemId;
+    const isDeleteButtonVisible =
+        canDelete ?? resource?.meta?.canDelete ?? resource?.canDelete;
+    const isEditButtonVisible =
+        canEdit ?? resource?.canEdit ?? !!resource?.edit;
+
+    const listButtonProps: ListButtonProps | undefined = hasList
+        ? {
+              resource: routerType === "legacy" ? resource?.route : identifier,
+          }
+        : undefined;
+    const editButtonProps: EditButtonProps | undefined = isEditButtonVisible
+        ? {
+              ...(isLoading ? { disabled: true } : {}),
+              type: "primary",
+              resource: routerType === "legacy" ? resource?.route : identifier,
+              recordItemId: id,
+          }
+        : undefined;
+    const deleteButtonProps: DeleteButtonProps | undefined =
+        isDeleteButtonVisible
+            ? {
+                  ...(isLoading ? { disabled: true } : {}),
+                  resource:
+                      routerType === "legacy" ? resource?.route : identifier,
+                  recordItemId: id,
+                  onSuccess: () => {
+                      if (routerType === "legacy") {
+                          legacyGoList(resource?.route ?? resource?.name ?? "");
+                      } else {
+                          go({ to: goListPath });
+                      }
+                  },
+                  dataProviderName,
+              }
+            : undefined;
+    const refreshButtonProps: RefreshButtonProps = {
+        ...(isLoading ? { disabled: true } : {}),
+        resource: routerType === "legacy" ? resource?.route : identifier,
+        recordItemId: id,
+        dataProviderName,
+    };
+
+    const defaultHeaderButtons = (
+        <>
+            {hasList && <ListButton {...listButtonProps} />}
+            {isEditButtonVisible && <EditButton {...editButtonProps} />}
+            {isDeleteButtonVisible && <DeleteButton {...deleteButtonProps} />}
+            <RefreshButton {...refreshButtonProps} />
+        </>
+    );
+
+    return (
+        <div {...(wrapperProps ?? {})}>
+            <PageHeader
+                ghost={false}
+                backIcon={goBackFromProps}
+                onBack={
+                    action !== "list" && typeof action !== "undefined"
+                        ? routerType === "legacy"
+                            ? goBack
+                            : back
+                        : undefined
+                }
+                title={
+                    title ??
+                    translate(
+                        `${identifier}.titles.show`,
+                        `Show ${getUserFriendlyName(
+                            resource?.meta?.label ??
+                                resource?.options?.label ??
+                                resource?.label ??
+                                identifier,
+                            "singular",
+                        )}`,
+                    )
+                }
+                extra={
+                    <Space
+                        key="extra-buttons"
+                        wrap
+                        {...(headerButtonProps ?? {})}
+                    >
+                        {headerButtons
+                            ? typeof headerButtons === "function"
+                                ? headerButtons({
+                                      defaultButtons: defaultHeaderButtons,
+                                      deleteButtonProps,
+                                      editButtonProps,
+                                      listButtonProps,
+                                      refreshButtonProps,
+                                  })
+                                : headerButtons
+                            : defaultHeaderButtons}
+                    </Space>
+                }
+                breadcrumb={
+                    typeof breadcrumb !== "undefined" ? (
+                        <>{breadcrumb}</> ?? undefined
+                    ) : (
+                        <Breadcrumb />
+                    )
+                }
+                {...(headerProps ?? {})}
+            >
+                <Spin spinning={isLoading}>
+                    <Card
+                        bordered={false}
+                        actions={
+                            footerButtons
+                                ? [
+                                      <Space
+                                          key="footer-buttons"
+                                          wrap
+                                          {...footerButtonProps}
+                                      >
+                                          {typeof footerButtons === "function"
+                                              ? footerButtons({
+                                                    defaultButtons: null,
+                                                })
+                                              : footerButtons}
+                                      </Space>,
+                                  ]
+                                : undefined
+                        }
+                        {...(contentProps ?? {})}
+                    >
+                        {children}
+                    </Card>
+                </Spin>
+            </PageHeader>
+        </div>
+    );
+};

+ 74 - 0
packages/antd/src/components/crud/types.ts

@@ -0,0 +1,74 @@
+import { CardProps, SpaceProps } from "antd";
+import {
+    CreateButtonProps,
+    DeleteButtonProps,
+    EditButtonProps,
+    ListButtonProps,
+    RefreshButtonProps,
+    SaveButtonProps,
+} from "../buttons/types";
+import {
+    RefineCrudCreateProps,
+    RefineCrudEditProps,
+    RefineCrudListProps,
+    RefineCrudShowProps,
+} from "@refinedev/ui-types";
+import { PageHeaderProps } from "../pageHeader";
+
+export type CreateProps = RefineCrudCreateProps<
+    SaveButtonProps,
+    SpaceProps,
+    SpaceProps,
+    React.DetailedHTMLProps<
+        React.HTMLAttributes<HTMLDivElement>,
+        HTMLDivElement
+    >,
+    PageHeaderProps,
+    CardProps
+>;
+
+export type EditProps = RefineCrudEditProps<
+    SaveButtonProps,
+    DeleteButtonProps,
+    SpaceProps,
+    SpaceProps,
+    React.DetailedHTMLProps<
+        React.HTMLAttributes<HTMLDivElement>,
+        HTMLDivElement
+    >,
+    PageHeaderProps,
+    CardProps,
+    {},
+    RefreshButtonProps,
+    ListButtonProps
+>;
+
+export type ListProps = RefineCrudListProps<
+    CreateButtonProps,
+    SpaceProps,
+    React.DetailedHTMLProps<
+        React.HTMLAttributes<HTMLDivElement>,
+        HTMLDivElement
+    >,
+    PageHeaderProps,
+    React.DetailedHTMLProps<
+        React.HTMLAttributes<HTMLDivElement>,
+        HTMLDivElement
+    >
+>;
+
+export type ShowProps = RefineCrudShowProps<
+    SpaceProps,
+    SpaceProps,
+    React.DetailedHTMLProps<
+        React.HTMLAttributes<HTMLDivElement>,
+        HTMLDivElement
+    >,
+    PageHeaderProps,
+    CardProps,
+    {},
+    EditButtonProps,
+    DeleteButtonProps,
+    RefreshButtonProps,
+    ListButtonProps
+>;

+ 54 - 0
packages/antd/src/components/fields/boolean/index.spec.tsx

@@ -0,0 +1,54 @@
+import React from "react";
+import { fieldBooleanTests } from "@refinedev/ui-tests";
+
+import { render, fireEvent } from "@test";
+import { BooleanField } from "./";
+
+describe("BooleanField", () => {
+    fieldBooleanTests.bind(this)(BooleanField);
+    describe("BooleanField with default props values", () => {
+        const initialValues = [true, false, "true", "false", "", undefined];
+
+        const results = ["true", "false", "true", "true", "false", "false"];
+
+        const iconClass = [
+            "anticon-check",
+            "anticon-close",
+            "anticon-check",
+            "anticon-check",
+            "anticon-close",
+            "anticon-close",
+        ];
+
+        initialValues.forEach((element, index) => {
+            const testName =
+                index === 2 || index === 3 || index === 4
+                    ? `"${initialValues[index]}"`
+                    : initialValues[index];
+
+            it(`renders boolean field value(${testName}) with correct tooltip text and icon`, async () => {
+                const baseDom = render(
+                    <div data-testid="default-field">
+                        <BooleanField value={element} />
+                    </div>,
+                );
+
+                fireEvent.mouseOver(
+                    baseDom.getByTestId("default-field").children[0],
+                );
+
+                expect(
+                    await baseDom.findByText(results[index]),
+                ).toBeInTheDocument();
+
+                expect(
+                    baseDom
+                        .getByTestId("default-field")
+                        .children[0].children[0].classList.contains(
+                            iconClass[index],
+                        ),
+                ).toBe(true);
+            });
+        });
+    });
+});

+ 26 - 0
packages/antd/src/components/fields/boolean/index.tsx

@@ -0,0 +1,26 @@
+import React from "react";
+import { Tooltip } from "antd";
+
+import { CheckOutlined, CloseOutlined } from "@ant-design/icons";
+
+import { BooleanFieldProps } from "../types";
+
+/**
+ * This field is used to display boolean values. It uses the {@link https://ant.design/components/tooltip/#header `<Tooltip>`} values from Ant Design.
+ *
+ * @see {@link https://refine.dev/docs/api-reference/antd/components/fields/boolean} for more details.
+ */
+export const BooleanField: React.FC<BooleanFieldProps> = ({
+    value,
+    valueLabelTrue = "true",
+    valueLabelFalse = "false",
+    trueIcon = <CheckOutlined />,
+    falseIcon = <CloseOutlined />,
+    ...rest
+}) => {
+    return (
+        <Tooltip title={value ? valueLabelTrue : valueLabelFalse} {...rest}>
+            {value ? <span>{trueIcon}</span> : <span>{falseIcon}</span>}
+        </Tooltip>
+    );
+};

+ 7 - 0
packages/antd/src/components/fields/date/index.spec.tsx

@@ -0,0 +1,7 @@
+import { fieldDateTests } from "@refinedev/ui-tests";
+
+import { DateField } from "./";
+
+describe("DateField", () => {
+    fieldDateTests.bind(this)(DateField);
+});

Some files were not shown because too many files changed in this diff