diff --git a/package-lock.json b/package-lock.json
index 9255ad6fc..7f16cbbcd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4060,6 +4060,10 @@
"resolved": "packages/sui-pde",
"link": true
},
+ "node_modules/@s-ui/performance": {
+ "resolved": "packages/sui-performance",
+ "link": true
+ },
"node_modules/@s-ui/polyfills": {
"resolved": "packages/sui-polyfills",
"link": true
@@ -12867,6 +12871,14 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/idlefy": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/idlefy/-/idlefy-1.1.1.tgz",
+ "integrity": "sha512-iV1kFRoiaN7XSFjErCLT5IB384kRhMv3AqPV7hZYpy2b62O/117QyIdBNemuq56flt/1wtaSCP0pFOFrk5oWiA==",
+ "funding": {
+ "url": "https://github.com/sponsors/harshkc"
+ }
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -24746,9 +24758,19 @@
"node": ">= 10"
}
},
+ "packages/sui-performance": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "idlefy": "1.1.1"
+ },
+ "devDependencies": {
+ "@s-ui/test": "8"
+ }
+ },
"packages/sui-polyfills": {
"name": "@s-ui/polyfills",
- "version": "1.21.0",
+ "version": "1.22.0",
"license": "MIT",
"dependencies": {
"core-js": "3",
diff --git a/packages/sui-performance/CHANGELOG.md b/packages/sui-performance/CHANGELOG.md
new file mode 100644
index 000000000..505d21df1
--- /dev/null
+++ b/packages/sui-performance/CHANGELOG.md
@@ -0,0 +1 @@
+# CHANGELOG
\ No newline at end of file
diff --git a/packages/sui-performance/README.md b/packages/sui-performance/README.md
new file mode 100644
index 000000000..939e388b6
--- /dev/null
+++ b/packages/sui-performance/README.md
@@ -0,0 +1,57 @@
+# @s-ui/performance
+
+> Performance utilities to make your web application go fast ⚡️
+
+## Installation
+
+```sh
+npm install @s-ui/performance
+```
+
+## Usage
+
+### Delay code execution
+
+Use this function to delay the execution of an expensive operation and prioritize user actions. Keep in mind that it only delays the response by a maximum of 1 frame, an average of 8ms, which is too little for a human to notice for the types of major actions where you’d use this function.
+
+```jsx
+import {delayTask} from '@s-ui/performance';
+
+export default function Example() {
+ const [counter, setCounter] = useState(0)
+
+ const handleClick = async () => {
+ setCounter(counter => counter + 1)
+
+ await delayTask()
+
+ work() // expensive work
+ }
+
+ return
+}
+```
+
+### Delay code execution until urgent
+
+Use this function to delay the execution of an expensive operation while the main thread is idle, using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and to prioritize user actions. This method ensures the execution is completed before the user leaves the page. It is especially useful for delaying tracking execution.
+
+The `delayTaskUntilUrgent` function optionally receives an options object. The documentation can be found [here](https://github.com/redbus-labs/idlefy/tree/main?tab=readme-ov-file#methods) ([idlefy](https://github.com/redbus-labs/idlefy/tree/main) is used under the hood).
+
+```jsx
+import {delayTaskUntilUrgent} from '@s-ui/performance';
+
+export default function Example() {
+ const [counter, setCounter] = useState(0)
+
+ const handleClick = async () => {
+ setCounter(counter => counter + 1)
+
+ await delayTaskUntilUrgent()
+
+ track() // expensive work
+ }
+
+ return
+}
+```
\ No newline at end of file
diff --git a/packages/sui-performance/package.json b/packages/sui-performance/package.json
new file mode 100644
index 000000000..bb438f55f
--- /dev/null
+++ b/packages/sui-performance/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@s-ui/performance",
+ "version": "1.0.0",
+ "description": "",
+ "type": "module",
+ "main": "lib/index.js",
+ "scripts": {
+ "lib": "babel --presets sui ./src --out-dir ./lib",
+ "prepublishOnly": "npm run lib",
+ "test:browser:watch": "NODE_ENV=test npm run test:browser -- --watch",
+ "test:browser": "NODE_ENV=test sui-test browser",
+ "test:server:watch": "npm run test:server -- --watch",
+ "test:server": "NODE_ENV=test sui-test server",
+ "test": "npm run test:server && npm run test:browser"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "idlefy": "1.1.1"
+ },
+ "peerDependencies": {},
+ "devDependencies": {
+ "@s-ui/test": "8"
+ }
+}
diff --git a/packages/sui-performance/src/index.js b/packages/sui-performance/src/index.js
new file mode 100644
index 000000000..6ef0e8728
--- /dev/null
+++ b/packages/sui-performance/src/index.js
@@ -0,0 +1,18 @@
+import {IdleQueue} from 'idlefy'
+
+const queue = new IdleQueue({ensureTasksRun: true})
+
+export function delayTask() {
+ return new Promise(resolve => {
+ setTimeout(resolve, 100)
+ requestAnimationFrame(() => {
+ setTimeout(resolve, 0)
+ })
+ })
+}
+
+export function delayTaskUntilUrgent(options) {
+ return new Promise(resolve => {
+ queue.pushTask(resolve, options)
+ })
+}
diff --git a/packages/sui-performance/test/browser/indexSpec.js b/packages/sui-performance/test/browser/indexSpec.js
new file mode 100644
index 000000000..36701fe47
--- /dev/null
+++ b/packages/sui-performance/test/browser/indexSpec.js
@@ -0,0 +1,26 @@
+import {expect} from 'chai'
+import sinon from 'sinon'
+
+import {waitFor} from '@testing-library/react'
+
+import {delayTask, delayTaskUntilUrgent} from '../../src/index.js'
+
+describe('delayTask', () => {
+ it('should execute function', async () => {
+ const callback = sinon.spy()
+
+ delayTask().then(callback)
+
+ await waitFor(() => expect(callback.called).to.be.true)
+ })
+})
+
+describe('delayTaskUntilUrgent', () => {
+ it('should execute function', async () => {
+ const callback = sinon.spy()
+
+ delayTaskUntilUrgent().then(callback)
+
+ await waitFor(() => expect(callback.called).to.be.true)
+ })
+})