diff --git a/.gitignore b/.gitignore
index 0ecea57..6f0fbb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,7 @@
.weather.json
node_modules
+prepare
@girs
+
+**/.claude/settings.local.json
diff --git a/app.ts b/app.ts
index 4b7f175..aa9ea1d 100644
--- a/app.ts
+++ b/app.ts
@@ -1,31 +1,27 @@
import './src/lib/session';
-import './src/scss/style';
-import './src/shared/useTheme';
-import './src/shared/wallpaper';
-import './src/shared/systray';
-import './src/shared/dropdown';
-import './src/shared/utilities';
-import './src/components/bar/utils/sideEffects';
-
+import './src/style';
+import 'src/core/behaviors/bar';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
-const hyprland = AstalHyprland.get_default();
-
import { Bar } from './src/components/bar';
-import { DropdownMenus, StandardWindows } from './src/components/menus/exports';
import Notifications from './src/components/notifications';
import SettingsDialog from './src/components/settings/index';
-import { bash, forMonitors } from 'src/lib/utils';
-import options from 'src/options';
import OSD from 'src/components/osd/index';
import { App } from 'astal/gtk3';
import { execAsync } from 'astal';
-import { handleRealization } from 'src/components/menus/shared/dropdown/helpers';
-import { isDropdownMenu } from 'src/lib/constants/options.js';
-import { initializeSystemBehaviors } from 'src/lib/behaviors';
-import { runCLI } from 'src/cli/commander';
+import { handleRealization } from 'src/components/menus/shared/dropdown/helpers/helpers';
+import { isDropdownMenu } from 'src/components/settings/constants.js';
+import { initializeSystemBehaviors } from 'src/core/behaviors';
+import { runCLI } from 'src/services/cli/commander';
+import { DropdownMenus, StandardWindows } from 'src/components/menus';
+import { forMonitors } from 'src/components/bar/utils/monitors';
+import options from 'src/configuration';
+import { SystemUtilities } from 'src/core/system/SystemUtilities';
+const hyprland = AstalHyprland.get_default();
const initializeStartupScripts = (): void => {
- execAsync(`python3 ${SRC_DIR}/scripts/bluetooth.py`).catch((err) => console.error(err));
+ execAsync(`python3 ${SRC_DIR}/scripts/bluetooth.py`).catch((err) =>
+ console.error('Failed to initialize bluetooth script:', err),
+ );
};
const initializeMenus = (): void => {
@@ -38,7 +34,10 @@ const initializeMenus = (): void => {
});
DropdownMenus.forEach((window) => {
- const windowName = window.name.replace('_default', '').concat('menu').toLowerCase();
+ const windowName = window.name
+ .replace(/_default.*/, '')
+ .concat('menu')
+ .toLowerCase();
if (!isDropdownMenu(windowName)) {
return;
@@ -54,18 +53,22 @@ App.start({
runCLI(request, res);
},
async main() {
- initializeStartupScripts();
+ try {
+ initializeStartupScripts();
- Notifications();
- OSD();
+ Notifications();
+ OSD();
- const barsForMonitors = await forMonitors(Bar);
- barsForMonitors.forEach((bar: JSX.Element) => bar);
+ const barsForMonitors = await forMonitors(Bar);
+ barsForMonitors.forEach((bar: JSX.Element) => bar);
- SettingsDialog();
- initializeMenus();
+ SettingsDialog();
+ initializeMenus();
- initializeSystemBehaviors();
+ initializeSystemBehaviors();
+ } catch (error) {
+ console.error('Error during application initialization:', error);
+ }
},
});
@@ -73,6 +76,6 @@ hyprland.connect('monitor-added', () => {
const { restartCommand } = options.hyprpanel;
if (options.hyprpanel.restartAgs.get()) {
- bash(restartCommand.get());
+ SystemUtilities.bash(restartCommand.get());
}
});
diff --git a/assets/tokyo-night.xml b/assets/tokyo-night.xml
new file mode 100644
index 0000000..0b597a7
--- /dev/null
+++ b/assets/tokyo-night.xml
@@ -0,0 +1,139 @@
+
+
+
+
+ HyprPanel - Jas Singh
+ Tokyo Night color scheme for GtkSourceView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/meson.build b/meson.build
index ed85f1f..2c1befb 100644
--- a/meson.build
+++ b/meson.build
@@ -41,4 +41,4 @@ configure_file(
install_subdir('scripts', install_dir: datadir)
install_subdir('themes', install_dir: datadir)
install_subdir('assets', install_dir: datadir)
-install_subdir('src/scss', install_dir: datadir / 'src')
+install_subdir('src/style', install_dir: datadir / 'src')
diff --git a/package-lock.json b/package-lock.json
index 879017c..a54c579 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,13 +12,14 @@
"astal": "/usr/share/astal/gjs"
},
"devDependencies": {
- "@types/node": "^22.5.4",
+ "@types/node": "^22.15.17",
"@typescript-eslint/eslint-plugin": "^8.5.0",
"@typescript-eslint/parser": "^8.5.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.2.1",
+ "knip": "^5.55.1",
"prettier": "^3.3.3",
"tsconfig-paths": "^4.2.0",
"typescript": "5.7.3"
@@ -28,11 +29,46 @@
"name": "astal",
"license": "LGPL-2.1"
},
+ "node_modules/@emnapi/core": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
+ "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.0.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
+ "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz",
+ "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
"integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
@@ -51,6 +87,7 @@
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
@@ -60,6 +97,7 @@
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -83,16 +121,28 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -105,6 +155,7 @@
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
@@ -115,6 +166,7 @@
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
@@ -129,6 +181,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -139,6 +192,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -151,6 +205,7 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=12.22"
},
@@ -164,13 +219,28 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead",
- "dev": true
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz",
+ "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.9.0"
+ }
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@@ -184,6 +254,7 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
@@ -193,6 +264,7 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@@ -201,11 +273,197 @@
"node": ">= 8"
}
},
+ "node_modules/@oxc-resolver/binding-darwin-arm64": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-9.0.2.tgz",
+ "integrity": "sha512-MVyRgP2gzJJtAowjG/cHN3VQXwNLWnY+FpOEsyvDepJki1SdAX/8XDijM1yN6ESD1kr9uhBKjGelC6h3qtT+rA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-darwin-x64": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-9.0.2.tgz",
+ "integrity": "sha512-7kV0EOFEZ3sk5Hjy4+bfA6XOQpCwbDiDkkHN4BHHyrBHsXxUR05EcEJPPL1WjItefg+9+8hrBmoK0xRoDs41+A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-freebsd-x64": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-9.0.2.tgz",
+ "integrity": "sha512-6OvkEtRXrt8sJ4aVfxHRikjain9nV1clIsWtJ1J3J8NG1ZhjyJFgT00SCvqxbK+pzeWJq6XzHyTCN78ML+lY2w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-9.0.2.tgz",
+ "integrity": "sha512-aYpNL6o5IRAUIdoweW21TyLt54Hy/ZS9tvzNzF6ya1ckOQ8DLaGVPjGpmzxdNja9j/bbV6aIzBH7lNcBtiOTkQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm64-gnu": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-9.0.2.tgz",
+ "integrity": "sha512-RGFW4vCfKMFEIzb9VCY0oWyyY9tR1/o+wDdNePhiUXZU4SVniRPQaZ1SJ0sUFI1k25pXZmzQmIP6cBmazi/Dew==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm64-musl": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-9.0.2.tgz",
+ "integrity": "sha512-lxx/PibBfzqYvut2Y8N2D0Ritg9H8pKO+7NUSJb9YjR/bfk2KRmP8iaUz3zB0JhPtf/W3REs65oKpWxgflGToA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-9.0.2.tgz",
+ "integrity": "sha512-yD28ptS/OuNhwkpXRPNf+/FvrO7lwURLsEbRVcL1kIE0GxNJNMtKgIE4xQvtKDzkhk6ZRpLho5VSrkkF+3ARTQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-s390x-gnu": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-9.0.2.tgz",
+ "integrity": "sha512-WBwEJdspoga2w+aly6JVZeHnxuPVuztw3fPfWrei2P6rNM5hcKxBGWKKT6zO1fPMCB4sdDkFohGKkMHVV1eryQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-x64-gnu": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-9.0.2.tgz",
+ "integrity": "sha512-a2z3/cbOOTUq0UTBG8f3EO/usFcdwwXnCejfXv42HmV/G8GjrT4fp5+5mVDoMByH3Ce3iVPxj1LmS6OvItKMYQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-x64-musl": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-9.0.2.tgz",
+ "integrity": "sha512-bHZF+WShYQWpuswB9fyxcgMIWVk4sZQT0wnwpnZgQuvGTZLkYJ1JTCXJMtaX5mIFHf69ngvawnwPIUA4Feil0g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-wasm32-wasi": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-9.0.2.tgz",
+ "integrity": "sha512-I5cSgCCh5nFozGSHz+PjIOfrqW99eUszlxKLgoNNzQ1xQ2ou9ZJGzcZ94BHsM9SpyYHLtgHljmOZxCT9bgxYNA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^0.2.9"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-resolver/binding-win32-arm64-msvc": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-9.0.2.tgz",
+ "integrity": "sha512-5IhoOpPr38YWDWRCA5kP30xlUxbIJyLAEsAK7EMyUgqygBHEYLkElaKGgS0X5jRXUQ6l5yNxuW73caogb2FYaw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-win32-x64-msvc": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-9.0.2.tgz",
+ "integrity": "sha512-Qc40GDkaad9rZksSQr2l/V9UubigIHsW69g94Gswc2sKYB3XfJXfIfyV8WTJ67u6ZMXsZ7BH1msSC6Aen75mCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@pkgr/core": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz",
"integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
@@ -217,36 +475,51 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
+ "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.15.17",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz",
- "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==",
+ "version": "22.15.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
+ "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
- "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz",
+ "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.32.0",
- "@typescript-eslint/type-utils": "8.32.0",
- "@typescript-eslint/utils": "8.32.0",
- "@typescript-eslint/visitor-keys": "8.32.0",
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/type-utils": "8.32.1",
+ "@typescript-eslint/utils": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"graphemer": "^1.4.0",
- "ignore": "^5.3.1",
+ "ignore": "^7.0.0",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.1.0"
},
@@ -264,15 +537,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz",
- "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
+ "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.32.0",
- "@typescript-eslint/types": "8.32.0",
- "@typescript-eslint/typescript-estree": "8.32.0",
- "@typescript-eslint/visitor-keys": "8.32.0",
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/typescript-estree": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4"
},
"engines": {
@@ -288,13 +562,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz",
- "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz",
+ "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.32.0",
- "@typescript-eslint/visitor-keys": "8.32.0"
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -305,13 +580,14 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz",
- "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz",
+ "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.32.0",
- "@typescript-eslint/utils": "8.32.0",
+ "@typescript-eslint/typescript-estree": "8.32.1",
+ "@typescript-eslint/utils": "8.32.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -328,10 +604,11 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz",
- "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz",
+ "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -341,13 +618,14 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz",
- "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz",
+ "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.32.0",
- "@typescript-eslint/visitor-keys": "8.32.0",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -367,15 +645,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz",
- "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz",
+ "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.32.0",
- "@typescript-eslint/types": "8.32.0",
- "@typescript-eslint/typescript-estree": "8.32.0"
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/typescript-estree": "8.32.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -390,12 +669,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.32.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz",
- "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz",
+ "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.32.0",
+ "@typescript-eslint/types": "8.32.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@@ -411,6 +691,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -422,13 +703,15 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
+ "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -441,6 +724,7 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
+ "license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
@@ -450,6 +734,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -466,6 +751,7 @@
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -475,6 +761,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -489,13 +776,15 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
+ "dev": true,
+ "license": "Python-2.0"
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"is-array-buffer": "^3.0.5"
@@ -512,6 +801,7 @@
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
"integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -532,6 +822,7 @@
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
"integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
@@ -553,6 +844,7 @@
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@@ -571,6 +863,7 @@
"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@@ -589,6 +882,7 @@
"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.1",
"call-bind": "^1.0.8",
@@ -614,6 +908,7 @@
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -623,6 +918,7 @@
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
@@ -637,13 +933,15 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -653,6 +951,7 @@
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
@@ -665,6 +964,7 @@
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
@@ -683,6 +983,7 @@
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
@@ -696,6 +997,7 @@
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
@@ -712,6 +1014,7 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -721,6 +1024,7 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -737,6 +1041,7 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -748,19 +1053,22 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -775,6 +1083,7 @@
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
@@ -792,6 +1101,7 @@
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
@@ -809,6 +1119,7 @@
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -822,10 +1133,11 @@
}
},
"node_modules/debug": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
- "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
@@ -842,13 +1154,15 @@
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
@@ -866,6 +1180,7 @@
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
@@ -883,6 +1198,7 @@
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
@@ -895,6 +1211,7 @@
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
@@ -905,27 +1222,28 @@
}
},
"node_modules/es-abstract": {
- "version": "1.23.9",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
- "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
+ "version": "1.23.10",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz",
+ "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.2",
"arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
+ "call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
+ "es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8",
- "get-intrinsic": "^1.2.7",
- "get-proto": "^1.0.0",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4",
"gopd": "^1.2.0",
@@ -941,13 +1259,13 @@
"is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1",
"is-typed-array": "^1.1.15",
- "is-weakref": "^1.1.0",
+ "is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0",
- "object-inspect": "^1.13.3",
+ "object-inspect": "^1.13.4",
"object-keys": "^1.1.1",
"object.assign": "^4.1.7",
"own-keys": "^1.0.1",
- "regexp.prototype.flags": "^1.5.3",
+ "regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0",
@@ -960,7 +1278,7 @@
"typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0",
- "which-typed-array": "^1.1.18"
+ "which-typed-array": "^1.1.19"
},
"engines": {
"node": ">= 0.4"
@@ -974,6 +1292,7 @@
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -983,6 +1302,7 @@
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -992,6 +1312,7 @@
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
@@ -1004,6 +1325,7 @@
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
@@ -1019,6 +1341,7 @@
"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
"integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
@@ -1031,6 +1354,7 @@
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-callable": "^1.2.7",
"is-date-object": "^1.0.5",
@@ -1048,6 +1372,7 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -1061,6 +1386,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -1116,6 +1442,7 @@
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
"integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
"dev": true,
+ "license": "MIT",
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@@ -1128,6 +1455,7 @@
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"debug": "^3.2.7",
"is-core-module": "^2.13.0",
@@ -1139,6 +1467,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
@@ -1148,6 +1477,7 @@
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
"integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"debug": "^3.2.7"
},
@@ -1165,6 +1495,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
@@ -1174,6 +1505,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.8",
@@ -1207,6 +1539,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -1217,6 +1550,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
@@ -1226,6 +1560,7 @@
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
@@ -1238,6 +1573,7 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
@@ -1250,6 +1586,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1262,6 +1599,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
@@ -1271,6 +1609,7 @@
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
@@ -1283,6 +1622,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.0.tgz",
"integrity": "sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.11.0"
@@ -1313,6 +1653,7 @@
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -1329,6 +1670,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -1341,16 +1683,28 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
+ "node_modules/eslint/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/eslint/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1363,6 +1717,7 @@
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
@@ -1380,6 +1735,7 @@
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
},
@@ -1392,6 +1748,7 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -1404,6 +1761,7 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
@@ -1413,6 +1771,7 @@
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -1421,19 +1780,22 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
- "dev": true
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -1450,6 +1812,7 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -1461,28 +1824,42 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
"integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
},
+ "node_modules/fd-package-json": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz",
+ "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "walk-up-path": "^3.0.1"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"flat-cache": "^3.0.4"
},
@@ -1495,6 +1872,7 @@
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1507,6 +1885,7 @@
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
@@ -1523,6 +1902,7 @@
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"flatted": "^3.2.9",
"keyv": "^4.5.3",
@@ -1536,13 +1916,15 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
@@ -1553,17 +1935,35 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/formatly": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.2.3.tgz",
+ "integrity": "sha512-WH01vbXEjh9L3bqn5V620xUAWs32CmK4IzWRRY6ep5zpa/mrisL4d9+pRVuETORVDTQw8OycSO1WC68PL51RaA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fd-package-json": "^1.2.0"
+ },
+ "bin": {
+ "formatly": "bin/index.mjs"
+ },
+ "engines": {
+ "node": ">=18.3.0"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
+ "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -1573,6 +1973,7 @@
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
@@ -1593,6 +1994,7 @@
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
+ "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -1602,6 +2004,7 @@
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
@@ -1626,6 +2029,7 @@
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
@@ -1639,6 +2043,7 @@
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
@@ -1657,6 +2062,7 @@
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
+ "license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -1677,6 +2083,7 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
@@ -1689,6 +2096,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -1699,6 +2107,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1711,6 +2120,7 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"type-fest": "^0.20.2"
},
@@ -1726,6 +2136,7 @@
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
@@ -1742,6 +2153,7 @@
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -1753,13 +2165,15 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
"integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -1772,6 +2186,7 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -1781,6 +2196,7 @@
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
@@ -1793,6 +2209,7 @@
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.0"
},
@@ -1808,6 +2225,7 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -1820,6 +2238,7 @@
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
@@ -1835,6 +2254,7 @@
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -1843,10 +2263,11 @@
}
},
"node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz",
+ "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 4"
}
@@ -1856,6 +2277,7 @@
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
@@ -1872,6 +2294,7 @@
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.8.19"
}
@@ -1882,6 +2305,7 @@
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dev": true,
+ "license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -1891,13 +2315,15 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"hasown": "^2.0.2",
@@ -1912,6 +2338,7 @@
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
@@ -1929,6 +2356,7 @@
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"async-function": "^1.0.0",
"call-bound": "^1.0.3",
@@ -1948,6 +2376,7 @@
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-bigints": "^1.0.2"
},
@@ -1963,6 +2392,7 @@
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
@@ -1979,6 +2409,7 @@
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -1991,6 +2422,7 @@
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
@@ -2006,6 +2438,7 @@
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"get-intrinsic": "^1.2.6",
@@ -2023,6 +2456,7 @@
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
@@ -2039,6 +2473,7 @@
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -2048,6 +2483,7 @@
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
@@ -2063,6 +2499,7 @@
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"get-proto": "^1.0.0",
@@ -2081,6 +2518,7 @@
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -2093,6 +2531,7 @@
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2105,6 +2544,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -2114,6 +2554,7 @@
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
@@ -2130,6 +2571,7 @@
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -2139,6 +2581,7 @@
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
@@ -2157,6 +2600,7 @@
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2169,6 +2613,7 @@
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
@@ -2184,6 +2629,7 @@
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
@@ -2200,6 +2646,7 @@
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-symbols": "^1.1.0",
@@ -2217,6 +2664,7 @@
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
@@ -2232,6 +2680,7 @@
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2244,6 +2693,7 @@
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
@@ -2259,6 +2709,7 @@
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
@@ -2274,19 +2725,32 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
+ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -2298,25 +2762,29 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
+ "license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
@@ -2329,15 +2797,77 @@
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
}
},
+ "node_modules/knip": {
+ "version": "5.58.1",
+ "resolved": "https://registry.npmjs.org/knip/-/knip-5.58.1.tgz",
+ "integrity": "sha512-9FKnuGhGFZ8wDgcjEYQ6btMmtGHa7dkvNU2ZHuMcv2NaxL7xDeFXZKjETbaiJBjWnLytrDXrh7a58lGXcE0Zfw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/webpro"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/knip"
+ },
+ {
+ "type": "polar",
+ "url": "https://polar.sh/webpro-nl"
+ }
+ ],
+ "license": "ISC",
+ "dependencies": {
+ "@nodelib/fs.walk": "^1.2.3",
+ "fast-glob": "^3.3.3",
+ "formatly": "^0.2.3",
+ "jiti": "^2.4.2",
+ "js-yaml": "^4.1.0",
+ "minimist": "^1.2.8",
+ "oxc-resolver": "^9.0.2",
+ "picocolors": "^1.1.0",
+ "picomatch": "^4.0.1",
+ "smol-toml": "^1.3.1",
+ "strip-json-comments": "5.0.1",
+ "zod": "^3.22.4",
+ "zod-validation-error": "^3.0.3"
+ },
+ "bin": {
+ "knip": "bin/knip.js",
+ "knip-bun": "bin/knip-bun.js"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18",
+ "typescript": ">=5.0.4"
+ }
+ },
+ "node_modules/knip/node_modules/strip-json-comments": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
+ "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1",
"type-check": "~0.4.0"
@@ -2351,6 +2881,7 @@
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"p-locate": "^5.0.0"
},
@@ -2365,13 +2896,15 @@
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -2381,6 +2914,7 @@
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
@@ -2390,6 +2924,7 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -2398,11 +2933,25 @@
"node": ">=8.6"
}
},
+ "node_modules/micromatch/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -2418,6 +2967,7 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
+ "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -2426,19 +2976,22 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2451,6 +3004,7 @@
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -2460,6 +3014,7 @@
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
@@ -2480,6 +3035,7 @@
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -2498,6 +3054,7 @@
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -2512,6 +3069,7 @@
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
@@ -2530,6 +3088,7 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"wrappy": "1"
}
@@ -2539,6 +3098,7 @@
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
@@ -2556,6 +3116,7 @@
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.6",
"object-keys": "^1.1.1",
@@ -2568,11 +3129,37 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/oxc-resolver": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-9.0.2.tgz",
+ "integrity": "sha512-w838ygc1p7rF+7+h5vR9A+Y9Fc4imy6C3xPthCMkdFUgFvUWkmABeNB8RBDQ6+afk44Q60/UMMQ+gfDUW99fBA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-resolver/binding-darwin-arm64": "9.0.2",
+ "@oxc-resolver/binding-darwin-x64": "9.0.2",
+ "@oxc-resolver/binding-freebsd-x64": "9.0.2",
+ "@oxc-resolver/binding-linux-arm-gnueabihf": "9.0.2",
+ "@oxc-resolver/binding-linux-arm64-gnu": "9.0.2",
+ "@oxc-resolver/binding-linux-arm64-musl": "9.0.2",
+ "@oxc-resolver/binding-linux-riscv64-gnu": "9.0.2",
+ "@oxc-resolver/binding-linux-s390x-gnu": "9.0.2",
+ "@oxc-resolver/binding-linux-x64-gnu": "9.0.2",
+ "@oxc-resolver/binding-linux-x64-musl": "9.0.2",
+ "@oxc-resolver/binding-wasm32-wasi": "9.0.2",
+ "@oxc-resolver/binding-win32-arm64-msvc": "9.0.2",
+ "@oxc-resolver/binding-win32-x64-msvc": "9.0.2"
+ }
+ },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
},
@@ -2588,6 +3175,7 @@
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"p-limit": "^3.0.2"
},
@@ -2603,6 +3191,7 @@
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
@@ -2615,6 +3204,7 @@
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -2624,6 +3214,7 @@
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -2633,6 +3224,7 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -2641,15 +3233,24 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8.6"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
@@ -2660,6 +3261,7 @@
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -2669,6 +3271,7 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.8.0"
}
@@ -2678,6 +3281,7 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -2693,6 +3297,7 @@
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
@@ -2705,6 +3310,7 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -2727,13 +3333,15 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@@ -2756,6 +3364,7 @@
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@@ -2776,6 +3385,7 @@
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
@@ -2796,6 +3406,7 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
@@ -2805,6 +3416,7 @@
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"dev": true,
+ "license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@@ -2816,6 +3428,7 @@
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
+ "license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
@@ -2845,6 +3458,7 @@
"url": "https://feross.org/support"
}
],
+ "license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
@@ -2854,6 +3468,7 @@
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
"integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
@@ -2873,6 +3488,7 @@
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"isarray": "^2.0.5"
@@ -2889,6 +3505,7 @@
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -2902,10 +3519,11 @@
}
},
"node_modules/semver": {
- "version": "7.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
- "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -2918,6 +3536,7 @@
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
@@ -2935,6 +3554,7 @@
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
@@ -2950,6 +3570,7 @@
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-errors": "^1.3.0",
@@ -2964,6 +3585,7 @@
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -2976,6 +3598,7 @@
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -2985,6 +3608,7 @@
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
@@ -3004,6 +3628,7 @@
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
@@ -3020,6 +3645,7 @@
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -3038,6 +3664,7 @@
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -3052,11 +3679,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/smol-toml": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz",
+ "integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/cyyynthia"
+ }
+ },
"node_modules/string.prototype.trim": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
@@ -3078,6 +3719,7 @@
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
@@ -3096,6 +3738,7 @@
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -3113,6 +3756,7 @@
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -3125,6 +3769,7 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
@@ -3134,6 +3779,7 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -3146,6 +3792,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -3158,6 +3805,7 @@
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -3166,13 +3814,13 @@
}
},
"node_modules/synckit": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz",
- "integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==",
+ "version": "0.11.6",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.6.tgz",
+ "integrity": "sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@pkgr/core": "^0.2.3",
- "tslib": "^2.8.1"
+ "@pkgr/core": "^0.2.4"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -3185,13 +3833,15 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -3204,6 +3854,7 @@
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
"integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=18.12"
},
@@ -3216,6 +3867,7 @@
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"json5": "^2.2.2",
"minimist": "^1.2.6",
@@ -3229,13 +3881,16 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true
+ "dev": true,
+ "license": "0BSD",
+ "optional": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1"
},
@@ -3248,6 +3903,7 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
+ "license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=10"
},
@@ -3260,6 +3916,7 @@
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
@@ -3274,6 +3931,7 @@
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"for-each": "^0.3.3",
@@ -3293,6 +3951,7 @@
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
@@ -3314,6 +3973,7 @@
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"for-each": "^0.3.3",
@@ -3334,6 +3994,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -3347,6 +4008,7 @@
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-bigints": "^1.0.2",
@@ -3364,22 +4026,32 @@
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
+ "node_modules/walk-up-path": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz",
+ "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
@@ -3395,6 +4067,7 @@
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-bigint": "^1.1.0",
"is-boolean-object": "^1.2.1",
@@ -3414,6 +4087,7 @@
"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"function.prototype.name": "^1.1.6",
@@ -3441,6 +4115,7 @@
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-map": "^2.0.3",
"is-set": "^2.0.3",
@@ -3459,6 +4134,7 @@
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
@@ -3480,6 +4156,7 @@
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -3488,19 +4165,44 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "3.25.30",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.30.tgz",
+ "integrity": "sha512-VolhdEtu6TJr/fzGuHA/SZ5ixvXqA6ADOG9VRcQ3rdOKmF5hkmcJbyaQjUH5BgmpA9gej++zYRX7zjSmdReIwA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.1.tgz",
+ "integrity": "sha512-1KP64yqDPQ3rupxNv7oXhf7KdhHHgaqbKuspVoiN93TT0xrBjql+Svjkdjq/Qh/7GSMmgQs3AfvBT0heE35thw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.24.4"
+ }
}
}
}
diff --git a/package.json b/package.json
index f91aa79..e107332 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,8 @@
"scripts": {
"lint": "eslint --config .eslintrc.json .",
"lint:fix": "eslint --config .eslintrc.json . --fix",
- "format": "prettier --write 'modules/**/*.ts'"
+ "format": "prettier --write 'modules/**/*.ts'",
+ "knip": "knip"
},
"keywords": [],
"author": "",
@@ -15,13 +16,14 @@
"astal": "/usr/share/astal/gjs"
},
"devDependencies": {
- "@types/node": "^22.5.4",
+ "@types/node": "^22.15.17",
"@typescript-eslint/eslint-plugin": "^8.5.0",
"@typescript-eslint/parser": "^8.5.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.2.1",
+ "knip": "^5.55.1",
"prettier": "^3.3.3",
"tsconfig-paths": "^4.2.0",
"typescript": "5.7.3"
diff --git a/src/cli/utils/BarVisibility.ts b/src/cli/utils/BarVisibility.ts
deleted file mode 100644
index 1b8ff12..0000000
--- a/src/cli/utils/BarVisibility.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { BarToggleStates } from 'src/lib/types/cli.types';
-
-export class BarVisibility {
- private static _toggleStates: BarToggleStates = {};
-
- public static get(barName: string): boolean {
- return this._toggleStates[barName] ?? true;
- }
-
- public static set(barName: string, isVisible: boolean): void {
- this._toggleStates[barName] = isVisible;
- }
-}
diff --git a/src/components/bar/custom_modules/CustomModules.ts b/src/components/bar/customModules/index.ts
similarity index 94%
rename from src/components/bar/custom_modules/CustomModules.ts
rename to src/components/bar/customModules/index.ts
index 4297c1e..9d64de2 100644
--- a/src/components/bar/custom_modules/CustomModules.ts
+++ b/src/components/bar/customModules/index.ts
@@ -1,8 +1,7 @@
import { Gio, readFileAsync } from 'astal';
-import { CustomBarModule } from './types';
+import { CustomBarModule, WidgetMap } from './types';
import { ModuleContainer } from './module_container';
-import { WidgetContainer } from '../shared/WidgetContainer';
-import { WidgetMap } from '..';
+import { WidgetContainer } from '../shared/widgetContainer';
export class CustomModules {
constructor() {}
diff --git a/src/components/bar/custom_modules/module_container/helpers/icon.ts b/src/components/bar/customModules/module_container/helpers/icon.ts
similarity index 98%
rename from src/components/bar/custom_modules/module_container/helpers/icon.ts
rename to src/components/bar/customModules/module_container/helpers/icon.ts
index 72680f8..8bc67e8 100644
--- a/src/components/bar/custom_modules/module_container/helpers/icon.ts
+++ b/src/components/bar/customModules/module_container/helpers/icon.ts
@@ -1,4 +1,4 @@
-import { isPrimitive } from 'src/lib/utils';
+import { isPrimitive } from 'src/lib/validation/types';
import { CustomBarModuleIcon } from '../../types';
import { parseCommandOutputJson } from './utils';
diff --git a/src/components/bar/custom_modules/module_container/helpers/label.ts b/src/components/bar/customModules/module_container/helpers/label.ts
similarity index 98%
rename from src/components/bar/custom_modules/module_container/helpers/label.ts
rename to src/components/bar/customModules/module_container/helpers/label.ts
index 3235f53..c6068c5 100644
--- a/src/components/bar/custom_modules/module_container/helpers/label.ts
+++ b/src/components/bar/customModules/module_container/helpers/label.ts
@@ -1,4 +1,4 @@
-import { isPrimitive } from 'src/lib/utils';
+import { isPrimitive } from 'src/lib/validation/types';
/**
* Generates a label based on module command output and a template configuration.
diff --git a/src/components/bar/custom_modules/module_container/helpers/utils.ts b/src/components/bar/customModules/module_container/helpers/utils.ts
similarity index 100%
rename from src/components/bar/custom_modules/module_container/helpers/utils.ts
rename to src/components/bar/customModules/module_container/helpers/utils.ts
diff --git a/src/components/bar/custom_modules/module_container/index.tsx b/src/components/bar/customModules/module_container/index.tsx
similarity index 95%
rename from src/components/bar/custom_modules/module_container/index.tsx
rename to src/components/bar/customModules/module_container/index.tsx
index c0f3067..2bd3244 100644
--- a/src/components/bar/custom_modules/module_container/index.tsx
+++ b/src/components/bar/customModules/module_container/index.tsx
@@ -1,11 +1,11 @@
import { CustomBarModule } from '../types';
-import { Module } from '../../shared/Module';
+import { Module } from '../../shared/module';
import { Astal } from 'astal/gtk3';
import { bind, Variable } from 'astal';
import { getIcon } from './helpers/icon';
import { getLabel } from './helpers/label';
import { initActionListener, initCommandPoller, setupModuleInteractions } from './setup';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
export const ModuleContainer = (moduleName: string, moduleMetadata: CustomBarModule): BarBoxChild => {
const {
diff --git a/src/components/bar/custom_modules/module_container/setup.ts b/src/components/bar/customModules/module_container/setup.ts
similarity index 93%
rename from src/components/bar/custom_modules/module_container/setup.ts
rename to src/components/bar/customModules/module_container/setup.ts
index dd80f2e..9b071a8 100644
--- a/src/components/bar/custom_modules/module_container/setup.ts
+++ b/src/components/bar/customModules/module_container/setup.ts
@@ -2,7 +2,9 @@ import { Variable, bind, execAsync } from 'astal';
import { Astal } from 'astal/gtk3';
import { BashPoller } from 'src/lib/poller/BashPoller';
import { CustomBarModule } from '../types';
-import { inputHandler } from '../../utils/helpers';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+
+const inputHandler = InputHandlerService.getInstance();
export function initCommandPoller(
commandOutput: Variable,
@@ -51,7 +53,7 @@ export function setupModuleInteractions(
moduleScrollThreshold: number,
): void {
const scrollThreshold = moduleScrollThreshold >= 0 ? moduleScrollThreshold : 1;
- inputHandler(
+ inputHandler.attachHandlers(
element,
{
onPrimaryClick: {
diff --git a/src/components/bar/custom_modules/types.ts b/src/components/bar/customModules/types.ts
similarity index 81%
rename from src/components/bar/custom_modules/types.ts
rename to src/components/bar/customModules/types.ts
index 07d112d..6f0ba68 100644
--- a/src/components/bar/custom_modules/types.ts
+++ b/src/components/bar/customModules/types.ts
@@ -1,4 +1,4 @@
-export type CustomBarModuleActions = {
+type CustomBarModuleActions = {
onLeftClick?: string;
onRightClick?: string;
onMiddleClick?: string;
@@ -18,3 +18,7 @@ export type CustomBarModule = {
actions?: CustomBarModuleActions;
};
export type CustomBarModuleIcon = string | string[] | Record;
+
+export type WidgetMap = {
+ [key in string]: (monitor: number) => JSX.Element;
+};
diff --git a/src/components/bar/exports.ts b/src/components/bar/exports.ts
deleted file mode 100644
index 530078d..0000000
--- a/src/components/bar/exports.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { Menu } from './modules/menu';
-import { Workspaces } from '../../components/bar/modules/workspaces/index';
-import { ClientTitle } from '../../components/bar/modules/window_title/index';
-import { Media } from '../../components/bar/modules/media/index';
-import { Notifications } from '../../components/bar/modules/notifications/index';
-import { Volume } from '../../components/bar/modules/volume/index';
-import { Network } from '../../components/bar/modules/network/index';
-import { Bluetooth } from '../../components/bar/modules/bluetooth/index';
-import { BatteryLabel } from '../../components/bar/modules/battery/index';
-import { Clock } from '../../components/bar/modules/clock/index';
-import { SysTray } from '../../components/bar/modules/systray/index';
-
-// Basic Modules
-import { Microphone } from '../../components/bar/modules/microphone/index';
-import { Ram } from '../../components/bar/modules/ram/index';
-import { Cpu } from '../../components/bar/modules/cpu/index';
-import { CpuTemp } from '../../components/bar/modules/cputemp/index';
-import { Storage } from '../../components/bar/modules/storage/index';
-import { Netstat } from '../../components/bar/modules/netstat/index';
-import { KbInput } from '../../components/bar/modules/kblayout/index';
-import { Updates } from '../../components/bar/modules/updates/index';
-import { Submap } from '../../components/bar/modules/submap/index';
-import { Weather } from '../../components/bar/modules/weather/index';
-import { Power } from '../../components/bar/modules/power/index';
-import { Hyprsunset } from '../../components/bar/modules/hyprsunset/index';
-import { Hypridle } from '../../components/bar/modules/hypridle/index';
-import { Cava } from '../../components/bar/modules/cava/index';
-import { WorldClock } from '../../components/bar/modules/worldclock/index';
-
-import { ModuleSeparator } from './modules/separator';
-
-export {
- Menu,
- Workspaces,
- ClientTitle,
- Media,
- Notifications,
- Volume,
- Network,
- Bluetooth,
- BatteryLabel,
- Clock,
- SysTray,
-
- // Basic Modules
- Microphone,
- Ram,
- Cpu,
- CpuTemp,
- Storage,
- Netstat,
- KbInput,
- Updates,
- Submap,
- Weather,
- Power,
- Hyprsunset,
- Hypridle,
- Cava,
- WorldClock,
- ModuleSeparator,
-};
diff --git a/src/components/bar/index.tsx b/src/components/bar/index.tsx
index 6cb4429..bfcc164 100644
--- a/src/components/bar/index.tsx
+++ b/src/components/bar/index.tsx
@@ -1,198 +1,19 @@
-import {
- Menu,
- Workspaces,
- ClientTitle,
- Media,
- Notifications,
- Volume,
- Network,
- Bluetooth,
- BatteryLabel,
- Clock,
- SysTray,
- Microphone,
- Ram,
- Cpu,
- CpuTemp,
- Storage,
- Netstat,
- KbInput,
- Updates,
- Submap,
- Weather,
- Power,
- Hyprsunset,
- Hypridle,
- Cava,
- WorldClock,
- ModuleSeparator,
-} from './exports';
+import { GdkMonitorService } from 'src/services/display/monitor';
+import { BarLayout } from './layout/BarLayout';
+import { getCoreWidgets } from './layout/coreWidgets';
+import { WidgetRegistry } from './layout/WidgetRegistry';
-import { WidgetContainer } from './shared/WidgetContainer';
-import options from 'src/options';
-import { App, Gtk } from 'astal/gtk3';
-
-import Astal from 'gi://Astal?version=3.0';
-import { bind, Variable } from 'astal';
-import { getLayoutForMonitor, isLayoutEmpty } from './utils/monitors';
-import { GdkMonitorMapper } from './utils/GdkMonitorMapper';
-import { CustomModules } from './custom_modules/CustomModules';
-import { idleInhibit } from 'src/shared/utilities';
-
-const { layouts } = options.bar;
-const { location } = options.theme.bar;
-const { location: borderLocation } = options.theme.bar.border;
-
-let widgets: WidgetMap = {
- battery: () => WidgetContainer(BatteryLabel()),
- dashboard: () => WidgetContainer(Menu()),
- workspaces: (monitor: number) => WidgetContainer(Workspaces(monitor)),
- windowtitle: () => WidgetContainer(ClientTitle()),
- media: () => WidgetContainer(Media()),
- notifications: () => WidgetContainer(Notifications()),
- volume: () => WidgetContainer(Volume()),
- network: () => WidgetContainer(Network()),
- bluetooth: () => WidgetContainer(Bluetooth()),
- clock: () => WidgetContainer(Clock()),
- systray: () => WidgetContainer(SysTray()),
- microphone: () => WidgetContainer(Microphone()),
- ram: () => WidgetContainer(Ram()),
- cpu: () => WidgetContainer(Cpu()),
- cputemp: () => WidgetContainer(CpuTemp()),
- storage: () => WidgetContainer(Storage()),
- netstat: () => WidgetContainer(Netstat()),
- kbinput: () => WidgetContainer(KbInput()),
- updates: () => WidgetContainer(Updates()),
- submap: () => WidgetContainer(Submap()),
- weather: () => WidgetContainer(Weather()),
- power: () => WidgetContainer(Power()),
- hyprsunset: () => WidgetContainer(Hyprsunset()),
- hypridle: () => WidgetContainer(Hypridle()),
- cava: () => WidgetContainer(Cava()),
- worldclock: () => WidgetContainer(WorldClock()),
- separator: () => ModuleSeparator(),
-};
-
-const gdkMonitorMapper = new GdkMonitorMapper();
+const gdkMonitorService = new GdkMonitorService();
+const widgetRegistry = new WidgetRegistry(getCoreWidgets());
+/**
+ * Factory function to create a Bar for a specific monitor
+ */
export const Bar = async (monitor: number): Promise => {
- try {
- const customWidgets = await CustomModules.build();
- widgets = {
- ...widgets,
- ...customWidgets,
- };
- } catch (error) {
- console.error(error);
- }
- const hyprlandMonitor = gdkMonitorMapper.mapGdkToHyprland(monitor);
+ await widgetRegistry.initialize();
- const computeVisibility = bind(layouts).as(() => {
- const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.get());
- return !isLayoutEmpty(foundLayout);
- });
+ const hyprlandMonitor = gdkMonitorService.mapGdkToHyprland(monitor);
+ const barLayout = new BarLayout(monitor, hyprlandMonitor, widgetRegistry);
- const computeClassName = bind(layouts).as(() => {
- const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.get());
- return !isLayoutEmpty(foundLayout) ? 'bar' : '';
- });
-
- const computeAnchor = bind(location).as((loc) => {
- if (loc === 'bottom') {
- return Astal.WindowAnchor.BOTTOM | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
- }
-
- return Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
- });
-
- const computeLayer = Variable.derive(
- [bind(options.theme.bar.layer), bind(options.tear)],
- (barLayer, tear) => {
- if (tear && barLayer === 'overlay') {
- return Astal.Layer.TOP;
- }
- const layerMap = {
- overlay: Astal.Layer.OVERLAY,
- top: Astal.Layer.TOP,
- bottom: Astal.Layer.BOTTOM,
- background: Astal.Layer.BACKGROUND,
- };
-
- return layerMap[barLayer];
- },
- );
-
- const computeBorderLocation = bind(borderLocation).as((brdrLcn) =>
- brdrLcn !== 'none' ? 'bar-panel withBorder' : 'bar-panel',
- );
-
- const leftBinding = Variable.derive([bind(layouts)], (currentLayouts) => {
- const foundLayout = getLayoutForMonitor(hyprlandMonitor, currentLayouts);
-
- return foundLayout.left
- .filter((mod) => Object.keys(widgets).includes(mod))
- .map((w) => widgets[w](hyprlandMonitor));
- });
- const middleBinding = Variable.derive([bind(layouts)], (currentLayouts) => {
- const foundLayout = getLayoutForMonitor(hyprlandMonitor, currentLayouts);
-
- return foundLayout.middle
- .filter((mod) => Object.keys(widgets).includes(mod))
- .map((w) => widgets[w](hyprlandMonitor));
- });
- const rightBinding = Variable.derive([bind(layouts)], (currentLayouts) => {
- const foundLayout = getLayoutForMonitor(hyprlandMonitor, currentLayouts);
-
- return foundLayout.right
- .filter((mod) => Object.keys(widgets).includes(mod))
- .map((w) => widgets[w](hyprlandMonitor));
- });
-
- return (
- {
- computeLayer.drop();
- leftBinding.drop();
- middleBinding.drop();
- rightBinding.drop();
- }}
- >
-
-
- {leftBinding()}
-
- }
- centerWidget={
-
- {middleBinding()}
-
- }
- endWidget={
-
- {rightBinding()}
-
- }
- />
-
-
- );
-};
-
-export type WidgetMap = {
- [K in string]: (monitor: number) => JSX.Element;
+ return barLayout.render();
};
diff --git a/src/components/bar/layout/BarLayout.tsx b/src/components/bar/layout/BarLayout.tsx
new file mode 100644
index 0000000..814fe2e
--- /dev/null
+++ b/src/components/bar/layout/BarLayout.tsx
@@ -0,0 +1,185 @@
+import { App, Gtk } from 'astal/gtk3';
+import Astal from 'gi://Astal?version=3.0';
+import { bind, Binding, Variable } from 'astal';
+import { idleInhibit } from 'src/lib/window/visibility';
+import { WidgetRegistry } from './WidgetRegistry';
+import { getLayoutForMonitor, isLayoutEmpty } from '../utils/monitors';
+import options from 'src/configuration';
+
+/**
+ * Responsible for the bar UI layout and positioning
+ */
+export class BarLayout {
+ private _hyprlandMonitor: number;
+ private _gdkMonitor: number;
+ private _widgetRegistry: WidgetRegistry;
+
+ private _visibilityVar: Variable;
+ private _classNameVar: Variable;
+ private _anchorVar: Variable;
+ private _layerVar: Variable;
+ private _borderLocationVar: Binding;
+ private _barSectionsVar: {
+ left: Variable;
+ middle: Variable;
+ right: Variable;
+ };
+
+ constructor(gdkMonitor: number, hyprlandMonitor: number, widgetRegistry: WidgetRegistry) {
+ this._gdkMonitor = gdkMonitor;
+ this._hyprlandMonitor = hyprlandMonitor;
+ this._widgetRegistry = widgetRegistry;
+
+ this._visibilityVar = Variable(true);
+ this._classNameVar = Variable('bar');
+ this._anchorVar = Variable(
+ Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT,
+ );
+ this._layerVar = Variable(Astal.Layer.TOP);
+ this._borderLocationVar = Variable('bar-panel')();
+ this._barSectionsVar = {
+ left: Variable([]),
+ middle: Variable([]),
+ right: Variable([]),
+ };
+
+ this._initializeReactiveVariables();
+ }
+
+ public render(): JSX.Element {
+ return (
+ this._cleanup()}
+ >
+
+
+ {this._barSectionsVar.left()}
+
+ }
+ centerWidget={
+
+ {this._barSectionsVar.middle()}
+
+ }
+ endWidget={
+
+ {this._barSectionsVar.right()}
+
+ }
+ />
+
+
+ );
+ }
+
+ private _initializeReactiveVariables(): void {
+ this._initializeVisibilityVariables();
+ this._initializePositionVariables();
+ this._initializeAppearanceVariables();
+ this._initializeSectionVariables();
+ }
+
+ private _initializeVisibilityVariables(): void {
+ const { layouts } = options.bar;
+
+ this._visibilityVar = Variable.derive([bind(layouts)], (currentLayouts) => {
+ const foundLayout = getLayoutForMonitor(this._hyprlandMonitor, currentLayouts);
+ return !isLayoutEmpty(foundLayout);
+ });
+
+ this._classNameVar = Variable.derive([bind(layouts)], (currentLayouts) => {
+ const foundLayout = getLayoutForMonitor(this._hyprlandMonitor, currentLayouts);
+ return !isLayoutEmpty(foundLayout) ? 'bar' : '';
+ });
+ }
+
+ /**
+ * Initialize variables related to bar positioning
+ */
+ private _initializePositionVariables(): void {
+ const { location } = options.theme.bar;
+
+ this._anchorVar = Variable.derive([bind(location)], (loc) => {
+ if (loc === 'bottom') {
+ return Astal.WindowAnchor.BOTTOM | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
+ }
+ return Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
+ });
+ }
+
+ private _initializeAppearanceVariables(): void {
+ const { location: borderLocation } = options.theme.bar.border;
+
+ this._layerVar = this._createLayerVariable();
+
+ this._borderLocationVar = bind(borderLocation).as((brdrLcn) =>
+ brdrLcn !== 'none' ? 'bar-panel withBorder' : 'bar-panel',
+ );
+ }
+
+ private _createLayerVariable(): Variable {
+ return Variable.derive([bind(options.theme.bar.layer), bind(options.tear)], (barLayer, tear) => {
+ if (tear && barLayer === 'overlay') {
+ return Astal.Layer.TOP;
+ }
+
+ return this._getLayerFromConfig(barLayer);
+ });
+ }
+
+ private _getLayerFromConfig(barLayer: string): Astal.Layer {
+ const layerMap: Record = {
+ overlay: Astal.Layer.OVERLAY,
+ top: Astal.Layer.TOP,
+ bottom: Astal.Layer.BOTTOM,
+ background: Astal.Layer.BACKGROUND,
+ };
+
+ return layerMap[barLayer] ?? Astal.Layer.TOP;
+ }
+
+ private _initializeSectionVariables(): void {
+ this._barSectionsVar = {
+ left: this._createSectionBinding('left'),
+ middle: this._createSectionBinding('middle'),
+ right: this._createSectionBinding('right'),
+ };
+ }
+
+ private _createSectionBinding(section: 'left' | 'middle' | 'right'): Variable {
+ const { layouts } = options.bar;
+
+ return Variable.derive([bind(layouts)], (currentLayouts) => {
+ const foundLayout = getLayoutForMonitor(this._hyprlandMonitor, currentLayouts);
+ return foundLayout[section]
+ .filter((mod) => this._widgetRegistry.hasWidget(mod))
+ .map((widget) => this._widgetRegistry.createWidget(widget, this._hyprlandMonitor));
+ });
+ }
+
+ private _cleanup(): void {
+ this._visibilityVar.drop();
+ this._classNameVar.drop();
+ this._anchorVar.drop();
+ this._layerVar.drop();
+
+ this._barSectionsVar.left.drop();
+ this._barSectionsVar.middle.drop();
+ this._barSectionsVar.right.drop();
+ }
+}
diff --git a/src/components/bar/layout/WidgetRegistry.tsx b/src/components/bar/layout/WidgetRegistry.tsx
new file mode 100644
index 0000000..e21f6b5
--- /dev/null
+++ b/src/components/bar/layout/WidgetRegistry.tsx
@@ -0,0 +1,55 @@
+import { CustomModules } from '../customModules';
+
+export type WidgetFactory = (monitor: number) => JSX.Element;
+
+/**
+ * Manages registration and creation of widgets
+ */
+export class WidgetRegistry {
+ private _widgets: Record = {};
+ private _initialized = false;
+
+ constructor(coreWidgets: Record) {
+ this._widgets = { ...coreWidgets };
+ }
+
+ /**
+ * Initialize the registry with core and custom widgets
+ */
+ public async initialize(): Promise {
+ if (this._initialized) return;
+
+ try {
+ const customWidgets = await CustomModules.build();
+
+ this._widgets = {
+ ...this._widgets,
+ ...customWidgets,
+ };
+
+ this._initialized = true;
+ } catch (error) {
+ console.error('Failed to initialize widget registry:', error);
+ throw error;
+ }
+ }
+
+ /**
+ * Check if a widget is registered
+ */
+ public hasWidget(name: string): boolean {
+ return Object.keys(this._widgets).includes(name);
+ }
+
+ /**
+ * Create an instance of a widget
+ */
+ public createWidget(name: string, monitor: number): JSX.Element {
+ if (!this.hasWidget(name)) {
+ console.error(`Widget "${name}" not found`);
+ return ;
+ }
+
+ return this._widgets[name](monitor);
+ }
+}
diff --git a/src/components/bar/layout/coreWidgets.tsx b/src/components/bar/layout/coreWidgets.tsx
new file mode 100644
index 0000000..f3be40e
--- /dev/null
+++ b/src/components/bar/layout/coreWidgets.tsx
@@ -0,0 +1,61 @@
+import { BatteryLabel } from '../modules/battery';
+import { Bluetooth } from '../modules/bluetooth';
+import { Cava } from '../modules/cava';
+import { Clock } from '../modules/clock';
+import { Cpu } from '../modules/cpu';
+import { CpuTemp } from '../modules/cputemp';
+import { Hypridle } from '../modules/hypridle';
+import { Hyprsunset } from '../modules/hyprsunset';
+import { KbInput } from '../modules/kblayout';
+import { Media } from '../modules/media';
+import { Menu } from '../modules/menu';
+import { Microphone } from '../modules/microphone';
+import { Netstat } from '../modules/netstat';
+import { Network } from '../modules/network';
+import { Notifications } from '../modules/notifications';
+import { Power } from '../modules/power';
+import { Ram } from '../modules/ram';
+import { ModuleSeparator } from '../modules/separator';
+import { Storage } from '../modules/storage';
+import { Submap } from '../modules/submap';
+import { SysTray } from '../modules/systray';
+import { Updates } from '../modules/updates';
+import { Volume } from '../modules/volume';
+import { Weather } from '../modules/weather';
+import { ClientTitle } from '../modules/window_title';
+import { Workspaces } from '../modules/workspaces';
+import { WorldClock } from '../modules/worldclock';
+import { WidgetContainer } from '../shared/widgetContainer';
+import { WidgetFactory } from './WidgetRegistry';
+
+export function getCoreWidgets(): Record {
+ return {
+ battery: () => WidgetContainer(BatteryLabel()),
+ dashboard: () => WidgetContainer(Menu()),
+ workspaces: (monitor: number) => WidgetContainer(Workspaces(monitor)),
+ windowtitle: () => WidgetContainer(ClientTitle()),
+ media: () => WidgetContainer(Media()),
+ notifications: () => WidgetContainer(Notifications()),
+ volume: () => WidgetContainer(Volume()),
+ network: () => WidgetContainer(Network()),
+ bluetooth: () => WidgetContainer(Bluetooth()),
+ clock: () => WidgetContainer(Clock()),
+ systray: () => WidgetContainer(SysTray()),
+ microphone: () => WidgetContainer(Microphone()),
+ ram: () => WidgetContainer(Ram()),
+ cpu: () => WidgetContainer(Cpu()),
+ cputemp: () => WidgetContainer(CpuTemp()),
+ storage: () => WidgetContainer(Storage()),
+ netstat: () => WidgetContainer(Netstat()),
+ kbinput: () => WidgetContainer(KbInput()),
+ updates: () => WidgetContainer(Updates()),
+ submap: () => WidgetContainer(Submap()),
+ weather: () => WidgetContainer(Weather()),
+ power: () => WidgetContainer(Power()),
+ hyprsunset: () => WidgetContainer(Hyprsunset()),
+ hypridle: () => WidgetContainer(Hypridle()),
+ cava: () => WidgetContainer(Cava()),
+ worldclock: () => WidgetContainer(WorldClock()),
+ separator: () => ModuleSeparator(),
+ };
+}
diff --git a/src/components/bar/modules/battery/helpers/index.ts b/src/components/bar/modules/battery/helpers/index.ts
index a620cbf..900cccb 100644
--- a/src/components/bar/modules/battery/helpers/index.ts
+++ b/src/components/bar/modules/battery/helpers/index.ts
@@ -1,4 +1,4 @@
-import { BatteryIconKeys, BatteryIcons } from 'src/lib/types/battery.types';
+import { BatteryIcons, BatteryIconKeys } from './types';
const batteryIcons: BatteryIcons = {
0: '',
diff --git a/src/lib/types/battery.types.ts b/src/components/bar/modules/battery/helpers/types.ts
similarity index 100%
rename from src/lib/types/battery.types.ts
rename to src/components/bar/modules/battery/helpers/types.ts
diff --git a/src/components/bar/modules/battery/index.tsx b/src/components/bar/modules/battery/index.tsx
index 719d216..f61f7f5 100644
--- a/src/components/bar/modules/battery/index.tsx
+++ b/src/components/bar/modules/battery/index.tsx
@@ -1,15 +1,17 @@
import AstalBattery from 'gi://AstalBattery?version=0.1';
import { Astal } from 'astal/gtk3';
-import { openMenu } from '../../utils/menu';
-import options from 'src/options';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
+import { openDropdownMenu } from '../../utils/menu';
import Variable from 'astal/variable';
import { bind } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { getBatteryIcon } from './helpers';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
const batteryService = AstalBattery.get_default();
+
const {
label: show_label,
rightClick,
@@ -136,7 +138,7 @@ const BatteryLabel = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'energymenu');
+ openDropdownMenu(clicked, event, 'energymenu');
}),
);
diff --git a/src/components/bar/modules/bluetooth/index.tsx b/src/components/bar/modules/bluetooth/index.tsx
index 7318ac5..0ef28af 100644
--- a/src/components/bar/modules/bluetooth/index.tsx
+++ b/src/components/bar/modules/bluetooth/index.tsx
@@ -1,11 +1,12 @@
-import options from 'src/options.js';
-import { openMenu } from '../../utils/menu.js';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { Variable, bind } from 'astal';
-import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
import AstalBluetooth from 'gi://AstalBluetooth?version=0.1';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types.js';
+import { BarBoxChild } from 'src/components/bar/types.js';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { openDropdownMenu } from '../../utils/menu';
+import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
const bluetoothService = AstalBluetooth.get_default();
@@ -90,7 +91,7 @@ const Bluetooth = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'bluetoothmenu');
+ openDropdownMenu(clicked, event, 'bluetoothmenu');
}),
);
diff --git a/src/components/bar/modules/cava/helpers.ts b/src/components/bar/modules/cava/helpers.ts
index d79607e..d713647 100644
--- a/src/components/bar/modules/cava/helpers.ts
+++ b/src/components/bar/modules/cava/helpers.ts
@@ -1,9 +1,8 @@
import { bind, Variable } from 'astal';
import AstalCava from 'gi://AstalCava?version=0.1';
import AstalMpris from 'gi://AstalMpris?version=0.1';
-import options from 'src/options';
+import options from 'src/configuration';
-const mprisService = AstalMpris.get_default();
const {
showActiveOnly,
bars,
@@ -24,6 +23,7 @@ const {
*/
export function initVisibilityTracker(isVis: Variable): Variable {
const cavaService = AstalCava.get_default();
+ const mprisService = AstalMpris.get_default();
return Variable.derive([bind(showActiveOnly), bind(mprisService, 'players')], (showActive, players) => {
isVis.set(cavaService !== null && (!showActive || players?.length > 0));
diff --git a/src/components/bar/modules/cava/index.tsx b/src/components/bar/modules/cava/index.tsx
index 9ef0142..c614ff7 100644
--- a/src/components/bar/modules/cava/index.tsx
+++ b/src/components/bar/modules/cava/index.tsx
@@ -1,11 +1,13 @@
import { Variable, bind } from 'astal';
import { Astal } from 'astal/gtk3';
-import { Module } from '../../shared/Module';
-import { inputHandler } from '../../utils/helpers';
-import options from 'src/options';
+import { Module } from '../../shared/module';
import { initSettingsTracker, initVisibilityTracker } from './helpers';
import AstalCava from 'gi://AstalCava?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+
+const inputHandler = InputHandlerService.getInstance();
const {
icon,
@@ -45,6 +47,8 @@ export const Cava = (): BarBoxChild => {
);
}
+ let inputHandlerBindings: Variable;
+
return Module({
isVis: bind(isVis),
label: labelBinding(),
@@ -53,7 +57,7 @@ export const Cava = (): BarBoxChild => {
boxClass: 'cava',
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -72,9 +76,10 @@ export const Cava = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
+ settingsTracker?.drop();
labelBinding.drop();
visTracker.drop();
- settingsTracker?.drop();
},
},
});
diff --git a/src/components/bar/modules/clock/index.tsx b/src/components/bar/modules/clock/index.tsx
index 1b985a0..8cd6cf6 100644
--- a/src/components/bar/modules/clock/index.tsx
+++ b/src/components/bar/modules/clock/index.tsx
@@ -1,11 +1,12 @@
-import { openMenu } from '../../utils/menu';
-import options from 'src/options';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
+import { openDropdownMenu } from '../../utils/menu';
import { bind, Variable } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { Astal } from 'astal/gtk3';
-import { systemTime } from 'src/shared/time';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { systemTime } from 'src/lib/units/time';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
const { format, icon, showIcon, showTime, rightClick, middleClick, scrollUp, scrollDown } = options.bar.clock;
const { style } = options.theme.bar.buttons;
@@ -83,7 +84,7 @@ const Clock = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'calendarmenu');
+ openDropdownMenu(clicked, event, 'calendarmenu');
}),
);
diff --git a/src/components/bar/modules/cpu/helpers/index.ts b/src/components/bar/modules/cpu/helpers/index.ts
deleted file mode 100644
index 6fbf669..0000000
--- a/src/components/bar/modules/cpu/helpers/index.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import GTop from 'gi://GTop';
-
-let previousCpuData = new GTop.glibtop_cpu();
-GTop.glibtop_get_cpu(previousCpuData);
-
-/**
- * Computes the CPU usage percentage.
- *
- * This function calculates the CPU usage percentage by comparing the current CPU data with the previous CPU data.
- * It calculates the differences in total and idle CPU times and uses these differences to compute the usage percentage.
- *
- * @returns The CPU usage percentage as a number.
- */
-export const computeCPU = (): number => {
- const currentCpuData = new GTop.glibtop_cpu();
- GTop.glibtop_get_cpu(currentCpuData);
-
- const totalDiff = currentCpuData.total - previousCpuData.total;
- const idleDiff = currentCpuData.idle - previousCpuData.idle;
-
- const cpuUsagePercentage = totalDiff > 0 ? ((totalDiff - idleDiff) / totalDiff) * 100 : 0;
-
- previousCpuData = currentCpuData;
-
- return cpuUsagePercentage;
-};
diff --git a/src/components/bar/modules/cpu/index.tsx b/src/components/bar/modules/cpu/index.tsx
index e87a035..b111702 100644
--- a/src/components/bar/modules/cpu/index.tsx
+++ b/src/components/bar/modules/cpu/index.tsx
@@ -1,25 +1,29 @@
-import { Module } from '../../shared/Module';
-import options from 'src/options';
-import { inputHandler } from 'src/components/bar/utils/helpers';
-import { computeCPU } from './helpers';
-import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import CpuUsageService from 'src/services/system/cpuUsage';
+
+const inputHandler = InputHandlerService.getInstance();
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } =
options.bar.customModules.cpu;
-export const cpuUsage = Variable(0);
-
-const cpuPoller = new FunctionPoller(cpuUsage, [bind(round)], bind(pollingInterval), computeCPU);
-
-cpuPoller.initialize('cpu');
+const cpuService = new CpuUsageService({ frequency: pollingInterval });
export const Cpu = (): BarBoxChild => {
- const labelBinding = Variable.derive([bind(cpuUsage), bind(round)], (cpuUsg: number, round: boolean) => {
- return round ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
- });
+ cpuService.initialize();
+
+ const labelBinding = Variable.derive(
+ [bind(cpuService.cpu), bind(round)],
+ (cpuUsg: number, round: boolean) => {
+ return round ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
+ },
+ );
+
+ let inputHandlerBindings: Variable;
const cpuModule = Module({
textIcon: bind(icon),
@@ -29,7 +33,7 @@ export const Cpu = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -48,7 +52,9 @@ export const Cpu = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
labelBinding.drop();
+ cpuService.destroy();
},
},
});
diff --git a/src/components/bar/modules/cputemp/helpers/index.ts b/src/components/bar/modules/cputemp/helpers/index.ts
index 2f493b1..c4153f6 100644
--- a/src/components/bar/modules/cputemp/helpers/index.ts
+++ b/src/components/bar/modules/cputemp/helpers/index.ts
@@ -1,44 +1,108 @@
-import { Variable } from 'astal';
+import { bind, Binding } from 'astal';
+import CpuTempService from 'src/services/system/cputemp';
+import { TemperatureConverter } from 'src/lib/units/temperature';
+import { CpuTempSensorDiscovery } from 'src/services/system/cputemp/sensorDiscovery';
+import options from 'src/configuration';
import GLib from 'gi://GLib?version=2.0';
-import { convertCelsiusToFahrenheit } from 'src/shared/weather';
-import options from 'src/options';
-import { UnitType } from 'src/lib/types/weather.types';
-const { sensor } = options.bar.customModules.cpuTemp;
+
+const { pollingInterval, sensor } = options.bar.customModules.cpuTemp;
/**
- * Retrieves the current CPU temperature.
- *
- * This function reads the CPU temperature from the specified sensor file and converts it to the desired unit (Celsius or Fahrenheit).
- * It also handles rounding the temperature value based on the provided `round` variable.
- *
- * @param round A Variable indicating whether to round the temperature value.
- * @param unit A Variable indicating the desired unit for the temperature (Celsius or Fahrenheit).
- *
- * @returns The current CPU temperature as a number. Returns 0 if an error occurs or the sensor file is empty.
+ * Creates a tooltip for the CPU temperature module showing sensor details
*/
-export const getCPUTemperature = (round: Variable, unit: Variable): number => {
- try {
- if (sensor.get().length === 0) {
- return 0;
+export function getCpuTempTooltip(cpuTempService: CpuTempService): Binding {
+ return bind(cpuTempService.temperature).as((temp) => {
+ const currentPath = cpuTempService.currentSensorPath;
+ const configuredSensor = sensor.get();
+ const isAuto = configuredSensor === 'auto' || configuredSensor === '';
+
+ const tempC = TemperatureConverter.fromCelsius(temp).formatCelsius();
+ const tempF = TemperatureConverter.fromCelsius(temp).formatFahrenheit();
+
+ const lines = [
+ 'CPU Temperature',
+ '─────────────────────────',
+ `Current: ${tempC} (${tempF})`,
+ '',
+ 'Sensor Information',
+ '─────────────────────────',
+ ];
+
+ if (currentPath) {
+ const sensorType = getSensorType(currentPath);
+ const sensorName = getSensorName(currentPath);
+ const chipName = getChipName(currentPath);
+
+ lines.push(`Mode: ${isAuto ? 'Auto-discovered' : 'User-configured'}`, `Type: ${sensorType}`);
+
+ if (chipName) {
+ lines.push(`Chip: ${chipName}`);
+ }
+
+ lines.push(`Device: ${sensorName}`, `Path: ${currentPath}`);
+ } else {
+ lines.push('Status: No sensor found', 'Try setting a manual sensor path');
}
- const [success, tempInfoBytes] = GLib.file_get_contents(sensor.get());
- const tempInfo = new TextDecoder('utf-8').decode(tempInfoBytes);
+ const interval = pollingInterval.get();
+ lines.push('', `Update interval: ${interval}ms`);
- if (!success || tempInfoBytes === null) {
- console.error(`Failed to read ${sensor.get()} or file content is null.`);
- return 0;
+ const allSensors = CpuTempSensorDiscovery.getAllSensors();
+ if (allSensors.length > 1) {
+ lines.push('', `Available sensors: ${allSensors.length}`);
}
- let decimalTemp = parseInt(tempInfo, 10) / 1000;
+ return lines.join('\n');
+ });
+}
- if (unit.get() === 'imperial') {
- decimalTemp = convertCelsiusToFahrenheit(decimalTemp);
- }
+/**
+ * Determines sensor type from path
+ */
+function getSensorType(path: string): string {
+ if (path.includes('/sys/class/hwmon/')) return 'Hardware Monitor';
+ if (path.includes('/sys/class/thermal/')) return 'Thermal Zone';
+ return 'Unknown';
+}
- return round.get() ? Math.round(decimalTemp) : parseFloat(decimalTemp.toFixed(2));
- } catch (error) {
- console.error('Error calculating CPU Temp:', error);
- return 0;
+/**
+ * Extracts sensor name from path
+ */
+function getSensorName(path: string): string {
+ if (path.includes('/sys/class/hwmon/')) {
+ const match = path.match(/hwmon(\d+)/);
+ return match ? `hwmon${match[1]}` : 'Unknown';
}
-};
+
+ if (path.includes('/sys/class/thermal/')) {
+ const match = path.match(/thermal_zone(\d+)/);
+ return match ? `thermal_zone${match[1]}` : 'Unknown';
+ }
+
+ return 'Unknown';
+}
+
+/**
+ * Gets the actual chip name for hwmon sensors
+ */
+function getChipName(path: string): string | undefined {
+ if (!path.includes('/sys/class/hwmon/')) return undefined;
+
+ try {
+ const match = path.match(/\/sys\/class\/hwmon\/hwmon\d+/);
+ if (!match) return undefined;
+
+ const nameFile = `${match[0]}/name`;
+ const [success, bytes] = GLib.file_get_contents(nameFile);
+
+ if (success && bytes) {
+ return new TextDecoder('utf-8').decode(bytes).trim();
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ console.debug(`Failed to get chip name: ${error.message}`);
+ }
+ }
+
+ return undefined;
+}
diff --git a/src/components/bar/modules/cputemp/index.tsx b/src/components/bar/modules/cputemp/index.tsx
index d21eca6..805b5bc 100644
--- a/src/components/bar/modules/cputemp/index.tsx
+++ b/src/components/bar/modules/cputemp/index.tsx
@@ -1,12 +1,14 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
-import { getCPUTemperature } from './helpers';
-import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { UnitType } from 'src/lib/types/weather.types';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import CpuTempService from 'src/services/system/cputemp';
+import options from 'src/configuration';
+import { TemperatureConverter } from 'src/lib/units/temperature';
+import { getCpuTempTooltip } from './helpers';
+
+const inputHandler = InputHandlerService.getInstance();
const {
label,
@@ -23,37 +25,51 @@ const {
icon,
} = options.bar.customModules.cpuTemp;
-export const cpuTemp = Variable(0);
-
-const cpuTempPoller = new FunctionPoller, Variable]>(
- cpuTemp,
- [bind(sensor), bind(round), bind(unit)],
- bind(pollingInterval),
- getCPUTemperature,
- round,
- unit,
-);
-
-cpuTempPoller.initialize('cputemp');
+const cpuTempService = new CpuTempService({ frequency: pollingInterval, sensor });
export const CpuTemp = (): BarBoxChild => {
+ cpuTempService.initialize();
+
+ const bindings = Variable.derive([bind(sensor), bind(round), bind(unit)], (sensorName) => {
+ cpuTempService.refresh();
+
+ if (cpuTempService.sensor.get() !== sensorName) {
+ cpuTempService.updateSensor(sensorName);
+ }
+ });
+
const labelBinding = Variable.derive(
- [bind(cpuTemp), bind(unit), bind(showUnit), bind(round)],
- (cpuTmp, tempUnit, shwUnit) => {
- const unitLabel = tempUnit === 'imperial' ? 'F' : 'C';
- const unit = shwUnit ? ` ${unitLabel}` : '';
- return `${cpuTmp.toString()}°${unit}`;
+ [bind(cpuTempService.temperature), bind(unit), bind(showUnit), bind(round)],
+ (cpuTemp, tempUnit, showUnit, roundValue) => {
+ const tempConverter = TemperatureConverter.fromCelsius(cpuTemp);
+ const isImperial = tempUnit === 'imperial';
+ const precision = roundValue ? 0 : 2;
+
+ if (showUnit) {
+ return isImperial
+ ? tempConverter.formatFahrenheit(precision)
+ : tempConverter.formatCelsius(precision);
+ }
+
+ const temp = isImperial
+ ? tempConverter.toFahrenheit(precision)
+ : tempConverter.toCelsius(precision);
+
+ return temp.toString();
},
);
+
+ let inputHandlerBindings: Variable;
+
const cpuTempModule = Module({
textIcon: bind(icon),
label: labelBinding(),
- tooltipText: 'CPU Temperature',
+ tooltipText: getCpuTempTooltip(cpuTempService),
boxClass: 'cpu-temp',
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -72,7 +88,10 @@ export const CpuTemp = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
+ cpuTempService.destroy();
labelBinding.drop();
+ bindings.drop();
},
},
});
diff --git a/src/components/bar/modules/hypridle/index.tsx b/src/components/bar/modules/hypridle/index.tsx
index c226c1d..c01ea1d 100644
--- a/src/components/bar/modules/hypridle/index.tsx
+++ b/src/components/bar/modules/hypridle/index.tsx
@@ -1,11 +1,13 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from '../../utils/helpers';
+import { Module } from '../../shared/module';
import Variable from 'astal/variable';
import { bind } from 'astal';
import { Astal } from 'astal/gtk3';
-import { idleInhibit } from 'src/shared/utilities';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { idleInhibit } from 'src/lib/window/visibility';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+
+const inputHandler = InputHandlerService.getInstance();
const { label, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } =
options.bar.customModules.hypridle;
@@ -29,6 +31,8 @@ export const Hypridle = (): BarBoxChild => {
},
);
+ let inputHandlerBindings: Variable;
+
const hypridleModule = Module({
textIcon: iconBinding(),
tooltipText: bind(idleInhibit).as(
@@ -39,7 +43,7 @@ export const Hypridle = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
fn: () => {
toggleInhibit();
@@ -60,6 +64,7 @@ export const Hypridle = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
iconBinding.drop();
labelBinding.drop();
},
diff --git a/src/components/bar/modules/hyprsunset/helpers/index.ts b/src/components/bar/modules/hyprsunset/helpers/index.ts
index 11c25da..7992390 100644
--- a/src/components/bar/modules/hyprsunset/helpers/index.ts
+++ b/src/components/bar/modules/hyprsunset/helpers/index.ts
@@ -1,5 +1,5 @@
import { execAsync, Variable } from 'astal';
-import options from 'src/options';
+import options from 'src/configuration';
const { temperature } = options.bar.customModules.hyprsunset;
@@ -9,7 +9,7 @@ const { temperature } = options.bar.customModules.hyprsunset;
* This command checks if the hyprsunset process is currently running by using the `pgrep` command.
* It returns 'yes' if the process is found and 'no' otherwise.
*/
-export const isActiveCommand = "bash -c \"pgrep -x 'hyprsunset' > /dev/null && echo 'yes' || echo 'no'\"";
+const isActiveCommand = "bash -c \"pgrep -x 'hyprsunset' > /dev/null && echo 'yes' || echo 'no'\"";
/**
* A variable to track the active state of the hyprsunset process.
diff --git a/src/components/bar/modules/hyprsunset/index.tsx b/src/components/bar/modules/hyprsunset/index.tsx
index 293c51a..86f7865 100644
--- a/src/components/bar/modules/hyprsunset/index.tsx
+++ b/src/components/bar/modules/hyprsunset/index.tsx
@@ -1,11 +1,14 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler, throttleInput } from 'src/components/bar/utils/helpers';
+import { Module } from '../../shared/module';
import { checkSunsetStatus, isActive, toggleSunset } from './helpers';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+import { throttleInput } from '../../utils/input/throttle';
+
+const inputHandler = InputHandlerService.getInstance();
const {
label,
@@ -55,6 +58,8 @@ export const Hyprsunset = (): BarBoxChild => {
},
);
+ let inputHandlerBindings: Variable;
+
const hyprsunsetModule = Module({
textIcon: iconBinding(),
tooltipText: tooltipBinding(),
@@ -63,7 +68,7 @@ export const Hyprsunset = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
fn: () => {
throttledToggleSunset();
@@ -84,6 +89,7 @@ export const Hyprsunset = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
iconBinding.drop();
tooltipBinding.drop();
labelBinding.drop();
diff --git a/src/components/bar/modules/kblayout/helpers/index.ts b/src/components/bar/modules/kblayout/helpers/index.ts
index 9965dd5..9d7538d 100644
--- a/src/components/bar/modules/kblayout/helpers/index.ts
+++ b/src/components/bar/modules/kblayout/helpers/index.ts
@@ -1,9 +1,5 @@
-import {
- HyprctlDeviceLayout,
- HyprctlKeyboard,
- KbLabelType,
-} from 'src/lib/types/customModules/kbLayout.types.js';
import { LayoutKeys, layoutMap, LayoutValues } from './layouts';
+import { KbLabelType, HyprctlDeviceLayout, HyprctlKeyboard } from './types';
/**
* Retrieves the keyboard layout from a given JSON string and format.
diff --git a/src/components/bar/modules/kblayout/helpers/layouts.ts b/src/components/bar/modules/kblayout/helpers/layouts.ts
index d280823..7f76165 100644
--- a/src/components/bar/modules/kblayout/helpers/layouts.ts
+++ b/src/components/bar/modules/kblayout/helpers/layouts.ts
@@ -1,4 +1,3 @@
-// Create a const object with all layouts
const layoutMapObj = {
'Abkhazian (Russia)': 'RU (Ab)',
Akan: 'GH (Akan)',
diff --git a/src/lib/types/customModules/kbLayout.types.ts b/src/components/bar/modules/kblayout/helpers/types.ts
similarity index 94%
rename from src/lib/types/customModules/kbLayout.types.ts
rename to src/components/bar/modules/kblayout/helpers/types.ts
index 8ca7985..c653475 100644
--- a/src/lib/types/customModules/kbLayout.types.ts
+++ b/src/components/bar/modules/kblayout/helpers/types.ts
@@ -12,7 +12,7 @@ export type HyprctlKeyboard = {
main: boolean;
};
-export type HyprctlMouse = {
+type HyprctlMouse = {
address: string;
name: string;
defaultSpeed: number;
diff --git a/src/components/bar/modules/kblayout/index.tsx b/src/components/bar/modules/kblayout/index.tsx
index 539a31c..ca4800f 100644
--- a/src/components/bar/modules/kblayout/index.tsx
+++ b/src/components/bar/modules/kblayout/index.tsx
@@ -1,12 +1,14 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
+import { Module } from '../../shared/module';
import { getKeyboardLayout } from './helpers';
-import { bind } from 'astal';
+import { bind, Variable } from 'astal';
import { useHook } from 'src/lib/shared/hookHandler';
import { Astal } from 'astal/gtk3';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+
+const inputHandler = InputHandlerService.getInstance();
const hyprlandService = AstalHyprland.get_default();
const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
@@ -22,6 +24,8 @@ function setLabel(self: Astal.Label): void {
}
export const KbInput = (): BarBoxChild => {
+ let inputHandlerBindings: Variable;
+
const keyboardModule = Module({
textIcon: bind(icon),
tooltipText: '',
@@ -43,7 +47,7 @@ export const KbInput = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -61,6 +65,9 @@ export const KbInput = (): BarBoxChild => {
},
});
},
+ onDestroy: () => {
+ inputHandlerBindings.drop();
+ },
},
});
diff --git a/src/components/bar/modules/media/helpers/index.ts b/src/components/bar/modules/media/helpers/index.ts
index 4f41165..4525480 100644
--- a/src/components/bar/modules/media/helpers/index.ts
+++ b/src/components/bar/modules/media/helpers/index.ts
@@ -1,7 +1,7 @@
import AstalMpris from 'gi://AstalMpris?version=0.1';
import { Variable } from 'astal';
-import { MediaTags } from 'src/lib/types/audio.types';
import { Opt } from 'src/lib/options';
+import { MediaTags } from './types';
/**
* Retrieves the icon for a given media player.
@@ -106,7 +106,10 @@ export const generateMediaLabel = (
if (!isValidMediaTag(p1)) {
return '';
}
- const value = p1 !== undefined ? mediaTags[p1] : '';
+ let value = p1 !== undefined ? mediaTags[p1] : '';
+
+ value = value?.replace(/\r?\n/g, ' ') ?? '';
+
const suffix = p2 !== undefined && p2.length > 0 ? p2.slice(1) : '';
return value ? value + suffix : '';
},
diff --git a/src/lib/types/audio.types.ts b/src/components/bar/modules/media/helpers/types.ts
similarity index 100%
rename from src/lib/types/audio.types.ts
rename to src/components/bar/modules/media/helpers/types.ts
diff --git a/src/components/bar/modules/media/index.tsx b/src/components/bar/modules/media/index.tsx
index 042ae51..61ec291 100644
--- a/src/components/bar/modules/media/index.tsx
+++ b/src/components/bar/modules/media/index.tsx
@@ -1,13 +1,14 @@
-import { openMenu } from '../../utils/menu.js';
-import options from 'src/options.js';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { generateMediaLabel } from './helpers/index.js';
-import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
+import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { activePlayer, mediaAlbum, mediaArtist, mediaTitle } from 'src/shared/media.js';
import AstalMpris from 'gi://AstalMpris?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types.js';
+import { BarBoxChild } from 'src/components/bar/types.js';
+import { activePlayer, mediaTitle, mediaAlbum, mediaArtist } from 'src/services/media';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { openDropdownMenu } from '../../utils/menu';
const mprisService = AstalMpris.get_default();
const {
@@ -103,7 +104,7 @@ const Media = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'mediamenu');
+ openDropdownMenu(clicked, event, 'mediamenu');
}),
);
diff --git a/src/components/bar/modules/menu/index.tsx b/src/components/bar/modules/menu/index.tsx
index 85f7c9c..4781edb 100644
--- a/src/components/bar/modules/menu/index.tsx
+++ b/src/components/bar/modules/menu/index.tsx
@@ -1,18 +1,20 @@
-import { runAsyncCommand, throttledScrollHandler } from '../../utils/helpers.js';
-import options from '../../../../options.js';
-import { openMenu } from '../../utils/menu.js';
-import { getDistroIcon } from '../../../../lib/utils.js';
import { Variable, bind } from 'astal';
-import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
+import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types.js';
+import { BarBoxChild } from 'src/components/bar/types.js';
+import { SystemUtilities } from 'src/core/system/SystemUtilities';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { openDropdownMenu } from '../../utils/menu';
const { rightClick, middleClick, scrollUp, scrollDown, autoDetectIcon, icon } = options.bar.launcher;
const Menu = (): BarBoxChild => {
const iconBinding = Variable.derive(
[autoDetectIcon, icon],
- (autoDetect: boolean, iconValue: string): string => (autoDetect ? getDistroIcon() : iconValue),
+ (autoDetect: boolean, iconValue: string): string =>
+ autoDetect ? SystemUtilities.getDistroIcon() : iconValue,
);
const componentClassName = bind(options.theme.bar.buttons.style).as((style: string) => {
@@ -60,7 +62,7 @@ const Menu = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'dashboardmenu');
+ openDropdownMenu(clicked, event, 'dashboardmenu');
}),
);
diff --git a/src/components/bar/modules/microphone/index.tsx b/src/components/bar/modules/microphone/index.tsx
index 6ac8dd6..64bd489 100644
--- a/src/components/bar/modules/microphone/index.tsx
+++ b/src/components/bar/modules/microphone/index.tsx
@@ -1,10 +1,12 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { inputHandler } from '../../utils/helpers';
import AstalWp from 'gi://AstalWp?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+
+const inputHandler = InputHandlerService.getInstance();
const wireplumber = AstalWp.get_default() as AstalWp.Wp;
const audioService = wireplumber.audio;
@@ -43,6 +45,9 @@ export const Microphone = (): BarBoxChild => {
return `${icon} ${description}`;
},
);
+
+ let inputHandlerBindings: Variable;
+
const microphoneModule = Module({
textIcon: iconBinding(),
label: bind(audioService.defaultMicrophone, 'volume').as((vol) => `${Math.round(vol * 100)}%`),
@@ -51,7 +56,7 @@ export const Microphone = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -69,6 +74,9 @@ export const Microphone = (): BarBoxChild => {
},
});
},
+ onDestroy: () => {
+ inputHandlerBindings.drop();
+ },
},
});
diff --git a/src/components/bar/modules/netstat/helpers.ts b/src/components/bar/modules/netstat/helpers.ts
new file mode 100644
index 0000000..b390f6d
--- /dev/null
+++ b/src/components/bar/modules/netstat/helpers.ts
@@ -0,0 +1,34 @@
+import NetworkUsageService from 'src/services/system/networkUsage';
+import { bind, Variable } from 'astal';
+import options from 'src/configuration';
+
+const { networkInterface, rateUnit, round, pollingInterval } = options.bar.customModules.netstat;
+
+export const setupNetworkServiceBindings = (): void => {
+ const networkService = new NetworkUsageService();
+
+ Variable.derive([bind(pollingInterval)], (interval) => {
+ networkService.updateTimer(interval);
+ })();
+
+ Variable.derive([bind(networkInterface)], (interfaceName) => {
+ networkService.setInterface(interfaceName);
+ })();
+
+ Variable.derive([bind(rateUnit)], (unit) => {
+ networkService.setRateUnit(unit);
+ })();
+
+ Variable.derive([bind(round)], (shouldRound) => {
+ networkService.setShouldRound(shouldRound);
+ })();
+};
+
+export const cycleArray = (array: T[], current: T, direction: 'next' | 'prev'): T => {
+ const currentIndex = array.indexOf(current);
+ const nextIndex =
+ direction === 'next'
+ ? (currentIndex + 1) % array.length
+ : (currentIndex - 1 + array.length) % array.length;
+ return array[nextIndex];
+};
diff --git a/src/components/bar/modules/netstat/helpers/index.ts b/src/components/bar/modules/netstat/helpers/index.ts
deleted file mode 100644
index 1c397bf..0000000
--- a/src/components/bar/modules/netstat/helpers/index.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import GLib from 'gi://GLib';
-import { Variable } from 'astal';
-import { RateUnit } from 'src/lib/types/bar.types';
-import { NetworkResourceData } from 'src/lib/types/customModules/network.types';
-import { getDefaultNetstatData } from 'src/lib/types/defaults/netstat.types';
-
-let previousNetUsage = { rx: 0, tx: 0, time: 0 };
-
-interface NetworkUsage {
- name: string;
- rx: number;
- tx: number;
-}
-
-/**
- * Formats the network rate based on the provided rate, type, and rounding option.
- *
- * This function converts the network rate to the appropriate unit (KiB/s, MiB/s, GiB/s, or bytes/s) based on the provided type.
- * It also rounds the rate to the specified number of decimal places.
- *
- * @param rate The network rate to format.
- * @param type The unit type for the rate (KiB, MiB, GiB).
- * @param round A boolean indicating whether to round the rate.
- *
- * @returns The formatted network rate as a string.
- */
-const formatRate = (rate: number, type: string, round: boolean): string => {
- const fixed = round ? 0 : 2;
-
- switch (true) {
- case type === 'KiB':
- return `${(rate / 1e3).toFixed(fixed)} KiB/s`;
- case type === 'MiB':
- return `${(rate / 1e6).toFixed(fixed)} MiB/s`;
- case type === 'GiB':
- return `${(rate / 1e9).toFixed(fixed)} GiB/s`;
- case rate >= 1e9:
- return `${(rate / 1e9).toFixed(fixed)} GiB/s`;
- case rate >= 1e6:
- return `${(rate / 1e6).toFixed(fixed)} MiB/s`;
- case rate >= 1e3:
- return `${(rate / 1e3).toFixed(fixed)} KiB/s`;
- default:
- return `${rate.toFixed(fixed)} bytes/s`;
- }
-};
-
-/**
- * Parses a line of network interface data.
- *
- * This function parses a line of network interface data from the /proc/net/dev file.
- * It extracts the interface name, received bytes, and transmitted bytes.
- *
- * @param line The line of network interface data to parse.
- *
- * @returns An object containing the interface name, received bytes, and transmitted bytes, or null if the line is invalid.
- */
-const parseInterfaceData = (line: string): NetworkUsage | null => {
- const trimmedLine = line.trim();
- if (!trimmedLine || trimmedLine.startsWith('Inter-') || trimmedLine.startsWith('face')) {
- return null;
- }
-
- const [iface, rx, , , , , , , , tx] = trimmedLine.split(/\s+/);
- const rxValue = parseInt(rx, 10);
- const txValue = parseInt(tx, 10);
- const cleanedIface = iface.replace(':', '');
-
- return { name: cleanedIface, rx: rxValue, tx: txValue };
-};
-
-/**
- * Validates a network interface.
- *
- * This function checks if the provided network interface is valid based on the interface name and received/transmitted bytes.
- *
- * @param iface The network interface to validate.
- * @param interfaceName The name of the interface to check.
- *
- * @returns True if the interface is valid, false otherwise.
- */
-const isValidInterface = (iface: NetworkUsage | null, interfaceName: string): boolean => {
- if (!iface) return false;
- if (interfaceName) return iface.name === interfaceName;
- return iface.name !== 'lo' && iface.rx > 0 && iface.tx > 0;
-};
-
-/**
- * Retrieves the network usage for a specified interface.
- *
- * This function reads the /proc/net/dev file to get the network usage data for the specified interface.
- * If no interface name is provided, it returns the usage data for the first valid interface found.
- *
- * @param interfaceName The name of the interface to get the usage data for. Defaults to an empty string.
- *
- * @returns An object containing the interface name, received bytes, and transmitted bytes.
- */
-const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
- const [success, data] = GLib.file_get_contents('/proc/net/dev');
- const defaultStats = { name: '', rx: 0, tx: 0 };
-
- if (!success) {
- console.error('Failed to read /proc/net/dev');
- return defaultStats;
- }
-
- const lines = new TextDecoder('utf-8').decode(data).split('\n');
-
- for (const line of lines) {
- const iface = parseInterfaceData(line);
-
- if (isValidInterface(iface, interfaceName)) {
- return iface ?? defaultStats;
- }
- }
-
- return { name: '', rx: 0, tx: 0 };
-};
-
-/**
- * Computes the network usage data.
- *
- * This function calculates the network usage data based on the provided rounding option, interface name, and data type.
- * It returns an object containing the formatted received and transmitted rates.
- *
- * @param round A Variable indicating whether to round the rates.
- * @param interfaceNameVar A Variable containing the name of the interface to get the usage data for.
- * @param dataType A Variable containing the unit type for the rates.
- *
- * @returns An object containing the formatted received and transmitted rates.
- */
-export const computeNetwork = (
- round: Variable,
- interfaceNameVar: Variable,
- dataType: Variable,
-): NetworkResourceData => {
- const rateUnit = dataType.get();
- const interfaceName = interfaceNameVar.get();
-
- const DEFAULT_NETSTAT_DATA = getDefaultNetstatData(rateUnit);
- try {
- const { rx, tx, name } = getNetworkUsage(interfaceName);
- const currentTime = Date.now();
-
- if (!name) {
- return DEFAULT_NETSTAT_DATA;
- }
-
- if (previousNetUsage.time === 0) {
- previousNetUsage = { rx, tx, time: currentTime };
- return DEFAULT_NETSTAT_DATA;
- }
-
- const timeDiff = Math.max((currentTime - previousNetUsage.time) / 1000, 1);
- const rxRate = (rx - previousNetUsage.rx) / timeDiff;
- const txRate = (tx - previousNetUsage.tx) / timeDiff;
-
- previousNetUsage = { rx, tx, time: currentTime };
-
- return {
- in: formatRate(rxRate, rateUnit, round.get()),
- out: formatRate(txRate, rateUnit, round.get()),
- };
- } catch (error) {
- console.error('Error calculating network usage:', error);
- return DEFAULT_NETSTAT_DATA;
- }
-};
diff --git a/src/components/bar/modules/netstat/index.tsx b/src/components/bar/modules/netstat/index.tsx
index fe9f2d4..7f93f91 100644
--- a/src/components/bar/modules/netstat/index.tsx
+++ b/src/components/bar/modules/netstat/index.tsx
@@ -1,91 +1,87 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
-import { computeNetwork } from './helpers';
-import { NETWORK_LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
-import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
+import { Module } from '../../shared/module';
+import NetworkUsageService from 'src/services/system/networkUsage';
import { bind, Variable } from 'astal';
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
import { Astal } from 'astal/gtk3';
-import { RateUnit, BarBoxChild, NetstatLabelType } from 'src/lib/types/bar.types';
-import { NetworkResourceData } from 'src/lib/types/customModules/network.types';
-import { getDefaultNetstatData } from 'src/lib/types/defaults/netstat.types';
+import { BarBoxChild } from '../../types';
+import { NetstatLabelType } from 'src/services/system/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+import { cycleArray, setupNetworkServiceBindings } from './helpers';
+
+const inputHandler = InputHandlerService.getInstance();
+const astalNetworkService = AstalNetwork.get_default();
+
+const NETWORK_LABEL_TYPES: NetstatLabelType[] = ['full', 'in', 'out'];
-const networkService = AstalNetwork.get_default();
const {
label,
labelType,
- networkInterface,
- rateUnit,
dynamicIcon,
icon,
networkInLabel,
networkOutLabel,
- round,
leftClick,
rightClick,
middleClick,
pollingInterval,
} = options.bar.customModules.netstat;
-export const networkUsage = Variable(getDefaultNetstatData(rateUnit.get()));
+setupNetworkServiceBindings();
-const netstatPoller = new FunctionPoller<
- NetworkResourceData,
- [round: Variable, interfaceNameVar: Variable, dataType: Variable]
->(
- networkUsage,
- [bind(rateUnit), bind(networkInterface), bind(round)],
- bind(pollingInterval),
- computeNetwork,
- round,
- networkInterface,
- rateUnit,
-);
-
-netstatPoller.initialize('netstat');
+const networkService = new NetworkUsageService({ frequency: pollingInterval });
export const Netstat = (): BarBoxChild => {
- const renderNetworkLabel = (lblType: NetstatLabelType, networkService: NetworkResourceData): string => {
+ networkService.initialize();
+
+ const renderNetworkLabel = (
+ lblType: NetstatLabelType,
+ networkData: { in: string; out: string },
+ ): string => {
switch (lblType) {
case 'in':
- return `${networkInLabel.get()} ${networkService.in}`;
+ return `${networkInLabel.get()} ${networkData.in}`;
case 'out':
- return `${networkOutLabel.get()} ${networkService.out}`;
+ return `${networkOutLabel.get()} ${networkData.out}`;
default:
- return `${networkInLabel.get()} ${networkService.in} ${networkOutLabel.get()} ${networkService.out}`;
+ return `${networkInLabel.get()} ${networkData.in} ${networkOutLabel.get()} ${networkData.out}`;
}
};
const iconBinding = Variable.derive(
- [bind(networkService, 'primary'), bind(networkService, 'wifi'), bind(networkService, 'wired')],
- (pmry, wfi, wrd) => {
- if (pmry === AstalNetwork.Primary.WIRED) {
- return wrd?.icon_name;
+ [
+ bind(astalNetworkService, 'primary'),
+ bind(astalNetworkService, 'wifi'),
+ bind(astalNetworkService, 'wired'),
+ ],
+ (primary, wifi, wired) => {
+ if (primary === AstalNetwork.Primary.WIRED) {
+ return wired?.icon_name;
}
- return wfi?.icon_name;
+ return wifi?.icon_name;
},
);
const labelBinding = Variable.derive(
- [bind(networkUsage), bind(labelType)],
- (networkService: NetworkResourceData, lblTyp: NetstatLabelType) =>
- renderNetworkLabel(lblTyp, networkService),
+ [bind(networkService.network), bind(labelType)],
+ (networkData, lblType: NetstatLabelType) => renderNetworkLabel(lblType, networkData),
);
+ let inputHandlerBindings: Variable;
+
const netstatModule = Module({
useTextIcon: bind(dynamicIcon).as((useDynamicIcon) => !useDynamicIcon),
icon: iconBinding(),
textIcon: bind(icon),
label: labelBinding(),
- tooltipText: bind(labelType).as((lblTyp) => {
- return lblTyp === 'full' ? 'Ingress / Egress' : lblTyp === 'in' ? 'Ingress' : 'Egress';
+ tooltipText: bind(labelType).as((lblType) => {
+ return lblType === 'full' ? 'Ingress / Egress' : lblType === 'in' ? 'Ingress' : 'Egress';
}),
boxClass: 'netstat',
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -97,31 +93,23 @@ export const Netstat = (): BarBoxChild => {
},
onScrollUp: {
fn: () => {
- labelType.set(
- NETWORK_LABEL_TYPES[
- (NETWORK_LABEL_TYPES.indexOf(labelType.get()) + 1) %
- NETWORK_LABEL_TYPES.length
- ] as NetstatLabelType,
- );
+ const nextLabelType = cycleArray(NETWORK_LABEL_TYPES, labelType.get(), 'next');
+ labelType.set(nextLabelType);
},
},
onScrollDown: {
fn: () => {
- labelType.set(
- NETWORK_LABEL_TYPES[
- (NETWORK_LABEL_TYPES.indexOf(labelType.get()) -
- 1 +
- NETWORK_LABEL_TYPES.length) %
- NETWORK_LABEL_TYPES.length
- ] as NetstatLabelType,
- );
+ const prevLabelType = cycleArray(NETWORK_LABEL_TYPES, labelType.get(), 'prev');
+ labelType.set(prevLabelType);
},
},
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
labelBinding.drop();
iconBinding.drop();
+ networkService.destroy();
},
},
});
diff --git a/src/components/bar/modules/network/index.tsx b/src/components/bar/modules/network/index.tsx
index 0ebd44d..3cc14ec 100644
--- a/src/components/bar/modules/network/index.tsx
+++ b/src/components/bar/modules/network/index.tsx
@@ -1,12 +1,13 @@
-import options from 'src/options';
-import { openMenu } from '../../utils/menu';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
+import { openDropdownMenu } from '../../utils/menu';
import { bind, Variable } from 'astal';
import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
import { Astal, Gtk } from 'astal/gtk3';
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
import { formatWifiInfo, wiredIcon, wirelessIcon } from './helpers';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
const networkService = AstalNetwork.get_default();
const { label, truncation, truncation_size, rightClick, middleClick, scrollDown, scrollUp, showWifiInfo } =
@@ -46,10 +47,7 @@ const Network = (): BarBoxChild => {
);
}
const networkWifi = networkService.wifi;
- if (networkWifi != null) {
- // Astal doesn't reset the wifi attributes on disconnect, only on a valid connection
- // so we need to check if both the WiFi is enabled and if there is an active access
- // point
+ if (networkWifi !== null) {
if (!networkWifi.enabled) {
return ;
}
@@ -127,7 +125,7 @@ const Network = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'networkmenu');
+ openDropdownMenu(clicked, event, 'networkmenu');
}),
);
diff --git a/src/components/bar/modules/notifications/index.tsx b/src/components/bar/modules/notifications/index.tsx
index f928235..922117c 100644
--- a/src/components/bar/modules/notifications/index.tsx
+++ b/src/components/bar/modules/notifications/index.tsx
@@ -1,12 +1,13 @@
import AstalNotifd from 'gi://AstalNotifd?version=0.1';
import { Astal, Gtk } from 'astal/gtk3';
-import { openMenu } from '../../utils/menu';
-import options from 'src/options';
-import { filterNotifications } from 'src/lib/shared/notifications.js';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
+import { openDropdownMenu } from '../../utils/menu';
import { bind, Variable } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { filterNotifications } from 'src/lib/shared/notifications';
const notifdService = AstalNotifd.get_default();
const { show_total, rightClick, middleClick, scrollUp, scrollDown, hideCountWhenZero } =
@@ -107,7 +108,7 @@ export const Notifications = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'notificationsmenu');
+ openDropdownMenu(clicked, event, 'notificationsmenu');
}),
);
diff --git a/src/components/bar/modules/power/index.tsx b/src/components/bar/modules/power/index.tsx
index ea09ed4..a7158f3 100644
--- a/src/components/bar/modules/power/index.tsx
+++ b/src/components/bar/modules/power/index.tsx
@@ -1,13 +1,17 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+
+const inputHandler = InputHandlerService.getInstance();
const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
export const Power = (): BarBoxChild => {
+ let inputHandlerBindings: Variable;
+
const powerModule = Module({
tooltipText: 'Power Menu',
textIcon: bind(icon),
@@ -15,7 +19,7 @@ export const Power = (): BarBoxChild => {
boxClass: 'powermodule',
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -33,6 +37,9 @@ export const Power = (): BarBoxChild => {
},
});
},
+ onDestroy: () => {
+ inputHandlerBindings.drop();
+ },
},
});
diff --git a/src/components/bar/modules/ram/helpers/index.ts b/src/components/bar/modules/ram/helpers/index.ts
deleted file mode 100644
index e334bce..0000000
--- a/src/components/bar/modules/ram/helpers/index.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { divide } from 'src/components/bar/utils/helpers';
-import { GLib, Variable } from 'astal';
-import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
-
-/**
- * Calculates the RAM usage.
- *
- * This function reads the memory information from the /proc/meminfo file and calculates the total, used, and available RAM.
- * It returns an object containing these values along with the percentage of used RAM.
- *
- * @param round A Variable indicating whether to round the percentage value.
- *
- * @returns An object containing the total, used, free RAM in bytes, and the percentage of used RAM.
- */
-export const calculateRamUsage = (round: Variable): GenericResourceData => {
- try {
- const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
-
- if (!success || meminfoBytes === null) {
- throw new Error('Failed to read /proc/meminfo or file content is null.');
- }
-
- const meminfo = new TextDecoder('utf-8').decode(meminfoBytes);
-
- const totalMatch = meminfo.match(/MemTotal:\s+(\d+)/);
- const availableMatch = meminfo.match(/MemAvailable:\s+(\d+)/);
-
- if (!totalMatch || !availableMatch) {
- throw new Error('Failed to parse /proc/meminfo for memory values.');
- }
-
- const totalRamInBytes = parseInt(totalMatch[1], 10) * 1024;
- const availableRamInBytes = parseInt(availableMatch[1], 10) * 1024;
-
- let usedRam = totalRamInBytes - availableRamInBytes;
- usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
-
- return {
- percentage: divide([totalRamInBytes, usedRam], round.get()),
- total: totalRamInBytes,
- used: usedRam,
- free: availableRamInBytes,
- };
- } catch (error) {
- console.error('Error calculating RAM usage:', error);
- return { total: 0, used: 0, percentage: 0, free: 0 };
- }
-};
diff --git a/src/components/bar/modules/ram/index.tsx b/src/components/bar/modules/ram/index.tsx
index ba1b03d..5a4da22 100644
--- a/src/components/bar/modules/ram/index.tsx
+++ b/src/components/bar/modules/ram/index.tsx
@@ -1,33 +1,25 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { calculateRamUsage } from './helpers';
-import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers';
-import { LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
-import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar.types';
-import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { renderResourceLabel, formatTooltip } from '../../utils/systemResource';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import { GenericResourceData, ResourceLabelType, LABEL_TYPES } from 'src/services/system/types';
+import RamUsageService from 'src/services/system/ramUsage';
+
+const inputHandler = InputHandlerService.getInstance();
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } =
options.bar.customModules.ram;
-const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
-const ramUsage = Variable(defaultRamData);
-
-const ramPoller = new FunctionPoller]>(
- ramUsage,
- [bind(round)],
- bind(pollingInterval),
- calculateRamUsage,
- round,
-);
-
-ramPoller.initialize('ram');
+const ramService = new RamUsageService({ frequency: pollingInterval });
export const Ram = (): BarBoxChild => {
+ ramService.initialize();
+
const labelBinding = Variable.derive(
- [bind(ramUsage), bind(labelType), bind(round)],
+ [bind(ramService.ram), bind(labelType), bind(round)],
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
@@ -35,6 +27,8 @@ export const Ram = (): BarBoxChild => {
},
);
+ let inputHandlerBindings: Variable;
+
const ramModule = Module({
textIcon: bind(icon),
label: labelBinding(),
@@ -45,7 +39,7 @@ export const Ram = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -77,7 +71,9 @@ export const Ram = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
labelBinding.drop();
+ ramService.destroy();
},
},
});
diff --git a/src/components/bar/modules/storage/helpers/index.ts b/src/components/bar/modules/storage/helpers/index.ts
deleted file mode 100644
index fb40f04..0000000
--- a/src/components/bar/modules/storage/helpers/index.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import GTop from 'gi://GTop';
-
-import { divide } from 'src/components/bar/utils/helpers';
-import { Variable } from 'astal';
-import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
-
-/**
- * Computes the storage usage for the root filesystem.
- *
- * This function calculates the total, used, and available storage for the root filesystem.
- * It returns an object containing these values along with the percentage of used storage.
- *
- * @param round A Variable indicating whether to round the percentage value.
- *
- * @returns An object containing the total, used, free storage in bytes, and the percentage of used storage.
- *
- * FIX: Consolidate with Storage service class
- */
-export const computeStorage = (round: Variable): GenericResourceData => {
- try {
- const currentFsUsage = new GTop.glibtop_fsusage();
-
- GTop.glibtop_get_fsusage(currentFsUsage, '/');
-
- const total = currentFsUsage.blocks * currentFsUsage.block_size;
- const available = currentFsUsage.bavail * currentFsUsage.block_size;
- const used = total - available;
-
- return {
- total,
- used,
- free: available,
- percentage: divide([total, used], round.get()),
- };
- } catch (error) {
- console.error('Error calculating RAM usage:', error);
- return { total: 0, used: 0, percentage: 0, free: 0 };
- }
-};
diff --git a/src/components/bar/modules/storage/helpers/tooltipFormatters.ts b/src/components/bar/modules/storage/helpers/tooltipFormatters.ts
new file mode 100644
index 0000000..6eb19cf
--- /dev/null
+++ b/src/components/bar/modules/storage/helpers/tooltipFormatters.ts
@@ -0,0 +1,90 @@
+import { DriveStorageData } from 'src/services/system/storage/types';
+import StorageService from 'src/services/system/storage';
+import { renderResourceLabel } from 'src/components/bar/utils/systemResource';
+import { SizeUnit } from 'src/lib/units/size/types';
+
+export type TooltipStyle = 'percentage-bar' | 'tree' | 'simple';
+
+/**
+ * Formats storage tooltip information based on the selected style
+ * @param paths - Array of mount paths to display
+ * @param storageService - The storage service instance
+ * @param style - The tooltip formatting style
+ * @param lblTyp - The label type for resource display
+ * @param round - Whether to round values
+ * @param sizeUnits - The size unit to use
+ */
+export function formatStorageTooltip(
+ paths: string[],
+ storageService: StorageService,
+ style: TooltipStyle,
+ round: boolean,
+ sizeUnits?: SizeUnit,
+): string {
+ const driveData = paths
+ .map((path) => storageService.getDriveInfo(path))
+ .filter((usage): usage is DriveStorageData => usage !== undefined);
+
+ switch (style) {
+ case 'percentage-bar':
+ return formatPercentageBarStyle(driveData, round, sizeUnits);
+ case 'tree':
+ return formatTreeStyle(driveData, round, sizeUnits);
+ case 'simple':
+ default:
+ return formatSimpleStyle(driveData, round, sizeUnits);
+ }
+}
+
+/**
+ * Creates a visual percentage bar using Unicode characters
+ * @param percentage - The percentage value (0-100)
+ */
+function generatePercentBar(percentage: number): string {
+ const filledBlocks = Math.round(percentage / 10);
+ const emptyBlocks = 10 - filledBlocks;
+ return '▰'.repeat(filledBlocks) + '▱'.repeat(emptyBlocks);
+}
+
+/**
+ * Formats tooltip with visual percentage bars
+ */
+function formatPercentageBarStyle(drives: DriveStorageData[], round: boolean, sizeUnits?: SizeUnit): string {
+ return drives
+ .map((usage) => {
+ const lbl = renderResourceLabel('used/total', usage, round, sizeUnits);
+ const percentBar = generatePercentBar(usage.percentage);
+ const displayName = usage.path === '/' ? '◉ System' : `◉ ${usage.name}`;
+
+ return `${displayName}\n ${percentBar} ${usage.percentage.toFixed(1)}%\n ${lbl}`;
+ })
+ .join('\n\n');
+}
+
+/**
+ * Formats tooltip with tree-like structure
+ */
+function formatTreeStyle(drives: DriveStorageData[], round: boolean, sizeUnits?: SizeUnit): string {
+ return drives
+ .map((usage) => {
+ const lbl = renderResourceLabel('used/total', usage, round, sizeUnits);
+ const displayName = usage.path === '/' ? 'System' : usage.name;
+
+ return `• ${displayName}: ${usage.percentage.toFixed(1)}%\n └─ ${lbl}`;
+ })
+ .join('\n');
+}
+
+/**
+ * Formats tooltip with simple text layout
+ */
+function formatSimpleStyle(drives: DriveStorageData[], round: boolean, sizeUnits?: SizeUnit): string {
+ return drives
+ .map((usage) => {
+ const lbl = renderResourceLabel('used/total', usage, round, sizeUnits);
+ const displayName = usage.path === '/' ? 'System' : usage.name;
+
+ return `[${displayName}]: ${lbl}`;
+ })
+ .join('\n');
+}
diff --git a/src/components/bar/modules/storage/index.tsx b/src/components/bar/modules/storage/index.tsx
index adc3fdd..c56004e 100644
--- a/src/components/bar/modules/storage/index.tsx
+++ b/src/components/bar/modules/storage/index.tsx
@@ -1,49 +1,68 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers';
-import { computeStorage } from './helpers';
-import { LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
-import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar.types';
-import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
+import options from 'src/configuration';
+import { renderResourceLabel } from '../../utils/systemResource';
+import { LABEL_TYPES, ResourceLabelType } from 'src/services/system/types';
+import { BarBoxChild } from '../../types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import StorageService from 'src/services/system/storage';
+import { formatStorageTooltip } from './helpers/tooltipFormatters';
-const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
- options.bar.customModules.storage;
+const inputHandler = InputHandlerService.getInstance();
-const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
-
-const storageUsage = Variable(defaultStorageData);
-
-const storagePoller = new FunctionPoller]>(
- storageUsage,
- [bind(round)],
- bind(pollingInterval),
- computeStorage,
+const {
+ label,
+ labelType,
+ icon,
round,
-);
+ leftClick,
+ rightClick,
+ middleClick,
+ pollingInterval,
+ units,
+ tooltipStyle,
+ paths,
+} = options.bar.customModules.storage;
-storagePoller.initialize('storage');
+const storageService = new StorageService({ frequency: pollingInterval, round, pathsToMonitor: paths });
export const Storage = (): BarBoxChild => {
+ const tooltipText = Variable('');
+
+ storageService.initialize();
+
const labelBinding = Variable.derive(
- [bind(storageUsage), bind(labelType), bind(round)],
- (storage, lblTyp, round) => {
- return renderResourceLabel(lblTyp, storage, round);
+ [bind(storageService.storage), bind(labelType), bind(paths), bind(tooltipStyle)],
+ (storage, lblTyp, filePaths) => {
+ const storageUnitToUse = units.get();
+ const sizeUnits = storageUnitToUse !== 'auto' ? storageUnitToUse : undefined;
+
+ const tooltipFormatted = formatStorageTooltip(
+ filePaths,
+ storageService,
+ tooltipStyle.get(),
+ round.get(),
+ sizeUnits,
+ );
+
+ tooltipText.set(tooltipFormatted);
+
+ return renderResourceLabel(lblTyp, storage, round.get(), sizeUnits);
},
);
+
+ let inputHandlerBindings: Variable;
+
const storageModule = Module({
textIcon: bind(icon),
label: labelBinding(),
- tooltipText: bind(labelType).as((lblTyp) => {
- return formatTooltip('Storage', lblTyp);
- }),
+ tooltipText: bind(tooltipText),
boxClass: 'storage',
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -75,6 +94,7 @@ export const Storage = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
labelBinding.drop();
},
},
diff --git a/src/components/bar/modules/submap/index.tsx b/src/components/bar/modules/submap/index.tsx
index 0faff05..1a74164 100644
--- a/src/components/bar/modules/submap/index.tsx
+++ b/src/components/bar/modules/submap/index.tsx
@@ -1,12 +1,14 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
-import { capitalizeFirstLetter } from 'src/lib/utils';
+import { Module } from '../../shared/module';
import { getInitialSubmap, isSubmapEnabled } from './helpers';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import options from 'src/configuration';
+import { capitalizeFirstLetter } from 'src/lib/string/formatters';
+import { BarBoxChild } from 'src/components/bar/types';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+
+const inputHandler = InputHandlerService.getInstance();
const hyprlandService = AstalHyprland.get_default();
const {
@@ -52,6 +54,8 @@ export const Submap = (): BarBoxChild => {
},
);
+ let inputHandlerBindings: Variable;
+
const submapModule = Module({
textIcon: submapIcon(),
tooltipText: submapLabel(),
@@ -60,7 +64,7 @@ export const Submap = (): BarBoxChild => {
boxClass: 'submap',
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -79,6 +83,7 @@ export const Submap = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
submapLabel.drop();
submapIcon.drop();
},
diff --git a/src/components/bar/modules/systray/index.tsx b/src/components/bar/modules/systray/index.tsx
index 8154223..4c13fb0 100644
--- a/src/components/bar/modules/systray/index.tsx
+++ b/src/components/bar/modules/systray/index.tsx
@@ -1,14 +1,14 @@
-import { isMiddleClick, isPrimaryClick, isSecondaryClick, Notify } from '../../../../lib/utils';
-import options from '../../../../options';
import AstalTray from 'gi://AstalTray?version=0.1';
import { bind, Gio, Variable } from 'astal';
import { Gdk, Gtk } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { isPrimaryClick, isSecondaryClick, isMiddleClick } from 'src/lib/events/mouse';
+import { SystemUtilities } from 'src/core/system/SystemUtilities';
const systemtray = AstalTray.get_default();
const { ignore, customIcons } = options.bar.systray;
-//TODO: Connect to `notify::menu-model` and `notify::action-group` to have up to date menu and action group
const createMenu = (menuModel: Gio.MenuModel, actionGroup: Gio.ActionGroup | null): Gtk.Menu => {
const menu = Gtk.Menu.new_from_model(menuModel);
menu.insert_action_group('dbusmenu', actionGroup);
@@ -31,7 +31,7 @@ const MenuDefaultIcon = ({ item }: MenuEntryProps): JSX.Element => {
return (
);
@@ -67,7 +67,7 @@ const MenuEntry = ({ item, child }: MenuEntryProps): JSX.Element => {
}
if (isMiddleClick(event)) {
- Notify({ summary: 'App Name', body: item.id });
+ SystemUtilities.notify({ summary: 'App Name', body: item.id });
}
}}
onDestroy={() => {
diff --git a/src/components/bar/modules/updates/index.tsx b/src/components/bar/modules/updates/index.tsx
index 5b29d5a..8f30ad6 100644
--- a/src/components/bar/modules/updates/index.tsx
+++ b/src/components/bar/modules/updates/index.tsx
@@ -1,10 +1,12 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
+import { Module } from '../../shared/module';
import { BashPoller } from 'src/lib/poller/BashPoller';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+
+const inputHandler = InputHandlerService.getInstance();
const {
updateCommand,
@@ -71,6 +73,8 @@ const updatesIcon = Variable.derive(
);
export const Updates = (): BarBoxChild => {
+ let inputHandlerBindings: Variable;
+
const updatesModule = Module({
textIcon: updatesIcon(),
tooltipText: bind(pendingUpdatesTooltip),
@@ -80,7 +84,7 @@ export const Updates = (): BarBoxChild => {
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(
+ inputHandlerBindings = inputHandler.attachHandlers(
self,
{
onPrimaryClick: {
@@ -102,6 +106,9 @@ export const Updates = (): BarBoxChild => {
postInputUpdater,
);
},
+ onDestroy: () => {
+ inputHandlerBindings.drop();
+ },
},
});
diff --git a/src/components/bar/modules/volume/index.tsx b/src/components/bar/modules/volume/index.tsx
index 7b0e3f8..1a4e366 100644
--- a/src/components/bar/modules/volume/index.tsx
+++ b/src/components/bar/modules/volume/index.tsx
@@ -1,12 +1,13 @@
-import { openMenu } from '../../utils/menu.js';
-import options from 'src/options';
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { bind, Variable } from 'astal';
-import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
+import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
import { getIcon } from './helpers/index.js';
import { Astal } from 'astal/gtk3';
import AstalWp from 'gi://AstalWp?version=0.1';
-import { BarBoxChild } from 'src/lib/types/bar.types.js';
+import { BarBoxChild } from 'src/components/bar/types.js';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
+import { openDropdownMenu } from '../../utils/menu';
const wireplumber = AstalWp.get_default() as AstalWp.Wp;
const audioService = wireplumber?.audio;
@@ -102,7 +103,7 @@ const Volume = (): BarBoxChild => {
disconnectFunctions.push(
onPrimaryClick(self, (clicked, event) => {
- openMenu(clicked, event, 'audiomenu');
+ openDropdownMenu(clicked, event, 'audiomenu');
}),
);
diff --git a/src/components/bar/modules/weather/index.tsx b/src/components/bar/modules/weather/index.tsx
index 5ab5633..4e71daa 100644
--- a/src/components/bar/modules/weather/index.tsx
+++ b/src/components/bar/modules/weather/index.tsx
@@ -1,37 +1,41 @@
-import options from 'src/options';
-import { Module } from '../../shared/Module';
-import { inputHandler } from 'src/components/bar/utils/helpers';
-import { getWeatherStatusTextIcon, globalWeatherVar } from 'src/shared/weather';
+import { Module } from '../../shared/module';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import WeatherService from 'src/services/weather';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+import options from 'src/configuration';
+import { toTitleCase } from 'src/lib/string/formatters';
+
+const inputHandler = InputHandlerService.getInstance();
+
+const weatherService = WeatherService.getInstance();
const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
options.bar.customModules.weather;
export const Weather = (): BarBoxChild => {
- const iconBinding = Variable.derive([bind(globalWeatherVar)], (wthr) => {
- const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
- return weatherStatusIcon;
+ const iconBinding = Variable.derive([bind(weatherService.statusIcon)], (icon) => {
+ return icon;
});
- const labelBinding = Variable.derive([bind(globalWeatherVar), bind(unit)], (wthr, unt) => {
- if (unt === 'imperial') {
- return `${Math.ceil(wthr.current.temp_f)}° F`;
- } else {
- return `${Math.ceil(wthr.current.temp_c)}° C`;
- }
+ const labelBinding = Variable.derive([bind(weatherService.temperature), bind(unit)], (temp) => {
+ return temp;
});
+ let inputHandlerBindings: Variable;
+
const weatherModule = Module({
textIcon: iconBinding(),
- tooltipText: bind(globalWeatherVar).as((v) => `Weather Status: ${v.current.condition.text}`),
+ tooltipText: bind(weatherService.weatherData).as(
+ (wthr) => `Weather Status: ${toTitleCase(wthr.current.condition.text)}`,
+ ),
boxClass: 'weather-custom',
label: labelBinding(),
showLabelBinding: bind(label),
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -50,6 +54,7 @@ export const Weather = (): BarBoxChild => {
});
},
onDestroy: () => {
+ inputHandlerBindings.drop();
iconBinding.drop();
labelBinding.drop();
},
diff --git a/src/lib/constants/appIcons.ts b/src/components/bar/modules/window_title/helpers/appIcons.ts
similarity index 100%
rename from src/lib/constants/appIcons.ts
rename to src/components/bar/modules/window_title/helpers/appIcons.ts
diff --git a/src/components/bar/modules/window_title/helpers/title.ts b/src/components/bar/modules/window_title/helpers/title.ts
index 2803262..8fc42af 100644
--- a/src/components/bar/modules/window_title/helpers/title.ts
+++ b/src/components/bar/modules/window_title/helpers/title.ts
@@ -1,8 +1,8 @@
-import options from 'src/options';
-import { capitalizeFirstLetter } from 'src/lib/utils';
-import { defaultWindowTitleMap } from 'src/lib/constants/appIcons';
+import { defaultWindowTitleMap } from 'src/components/bar/modules/window_title/helpers/appIcons';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { bind, Variable } from 'astal';
+import options from 'src/configuration';
+import { capitalizeFirstLetter } from 'src/lib/string/formatters';
const { title_map: userDefinedTitles } = options.bar.windowtitle;
diff --git a/src/components/bar/modules/window_title/index.tsx b/src/components/bar/modules/window_title/index.tsx
index 27198ff..823d93a 100644
--- a/src/components/bar/modules/window_title/index.tsx
+++ b/src/components/bar/modules/window_title/index.tsx
@@ -1,11 +1,12 @@
-import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers';
-import options from 'src/options';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { bind, Variable } from 'astal';
import { clientTitle, getTitle, getWindowMatch, truncateTitle } from './helpers/title';
import { Astal } from 'astal/gtk3';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { runAsyncCommand } from '../../utils/input/commandExecutor';
+import { throttledScrollHandler } from '../../utils/input/throttle';
const hyprlandService = AstalHyprland.get_default();
const { leftClick, rightClick, middleClick, scrollDown, scrollUp } = options.bar.windowtitle;
diff --git a/src/components/bar/modules/workspaces/helpers/index.ts b/src/components/bar/modules/workspaces/helpers/index.ts
index 2a0b525..807dfdd 100644
--- a/src/components/bar/modules/workspaces/helpers/index.ts
+++ b/src/components/bar/modules/workspaces/helpers/index.ts
@@ -1,406 +1,278 @@
-import { Variable } from 'astal';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
-import { MonitorMap, WorkspaceMonitorMap, WorkspaceRule } from 'src/lib/types/workspace.types';
-import { range } from 'src/lib/utils';
-import options from 'src/options';
+import options from 'src/configuration';
+import { defaultApplicationIconMap } from 'src/components/bar/modules/window_title/helpers/appIcons';
+import { isValidGjsColor } from 'src/lib/validation/colors';
+import { AppIconOptions } from './types';
+import { WorkspaceIconMap } from '../types';
+import { unique } from 'src/lib/array/helpers';
const hyprlandService = AstalHyprland.get_default();
-const { workspaces, reverse_scroll, ignored } = options.bar.workspaces;
+const { monochrome, background } = options.theme.bar.buttons;
+const { background: wsBackground, active } = options.theme.bar.buttons.workspaces;
+
+const { showWsIcons, showAllActive, numbered_active_indicator: wsActiveIndicator } = options.bar.workspaces;
/**
- * A Variable that holds the current map of monitors to the workspace numbers assigned to them.
+ * Determines if a workspace is active on a given monitor.
+ *
+ * This function checks if the workspace with the specified index is currently active on the given monitor.
+ * It uses the `showAllActive` setting and the `hyprlandService` to determine the active workspace on the monitor.
+ *
+ * @param monitor The index of the monitor to check.
+ * @param i The index of the workspace to check.
+ *
+ * @returns True if the workspace is active on the monitor, false otherwise.
*/
-export const workspaceRules = Variable(getWorkspaceMonitorMap());
-
-/**
- * A Variable used to force UI or other updates when relevant workspace events occur.
- */
-export const forceUpdater = Variable(true);
-
-/**
- * Retrieves the workspace numbers associated with a specific monitor.
- *
- * If only one monitor exists, this will simply return a list of all possible workspaces.
- * Otherwise, it will consult the workspace rules to determine which workspace numbers
- * belong to the specified monitor.
- *
- * @param monitorId - The numeric identifier of the monitor.
- *
- * @returns An array of workspace numbers belonging to the specified monitor.
- */
-export function getWorkspacesForMonitor(monitorId: number): number[] {
- const allMonitors = hyprlandService.get_monitors();
-
- if (allMonitors.length === 1) {
- return Array.from({ length: workspaces.get() }, (_, index) => index + 1);
- }
-
- const workspaceMonitorRules = getWorkspaceMonitorMap();
-
- const monitorNameMap: MonitorMap = {};
- allMonitors.forEach((monitorInstance) => {
- monitorNameMap[monitorInstance.id] = monitorInstance.name;
- });
-
- const currentMonitorName = monitorNameMap[monitorId];
-
- return workspaceMonitorRules[currentMonitorName];
-}
-
-/**
- * Checks whether a given workspace is valid (assigned) for the specified monitor.
- *
- * This function inspects the workspace rules object to determine if the current workspace belongs
- * to the target monitor. If no workspace rules exist, the function defaults to returning `true`.
- *
- * @param workspaceId - The number representing the current workspace.
- * @param workspaceMonitorRules - The map of monitor names to assigned workspace numbers.
- * @param monitorId - The numeric identifier for the monitor.
- * @param workspaceList - A list of Hyprland workspace objects.
- * @param monitorList - A list of Hyprland monitor objects.
- *
- * @returns `true` if the workspace is assigned to the monitor or if no rules exist. Otherwise, `false`.
- */
-function isWorkspaceValidForMonitor(
- workspaceId: number,
- workspaceMonitorRules: WorkspaceMonitorMap,
- monitorId: number,
- workspaceList: AstalHyprland.Workspace[],
- monitorList: AstalHyprland.Monitor[],
-): boolean {
- const monitorNameMap: MonitorMap = {};
- const allWorkspaceInstances = workspaceList ?? [];
-
- const workspaceMonitorReferences = allWorkspaceInstances
- .filter((workspaceInstance) => workspaceInstance !== null)
- .map((workspaceInstance) => {
- return {
- id: workspaceInstance.monitor?.id,
- name: workspaceInstance.monitor?.name,
- };
- });
-
- const mergedMonitorInstances = [
- ...new Map(
- [...workspaceMonitorReferences, ...monitorList].map((monitorCandidate) => [
- monitorCandidate.id,
- monitorCandidate,
- ]),
- ).values(),
- ];
-
- mergedMonitorInstances.forEach((monitorInstance) => {
- monitorNameMap[monitorInstance.id] = monitorInstance.name;
- });
-
- const currentMonitorName = monitorNameMap[monitorId];
- const currentMonitorWorkspaceRules = workspaceMonitorRules[currentMonitorName] ?? [];
- const activeWorkspaceIds = new Set(allWorkspaceInstances.map((ws) => ws.id));
- const filteredWorkspaceRules = currentMonitorWorkspaceRules.filter((ws) => !activeWorkspaceIds.has(ws));
-
- if (filteredWorkspaceRules === undefined) {
- return false;
- }
-
- return filteredWorkspaceRules.includes(workspaceId);
-}
-
-/**
- * Fetches a map of monitors to the workspace numbers that belong to them.
- *
- * This function communicates with the Hyprland service to retrieve workspace rules in JSON format.
- * Those rules are parsed, and a map of monitor names to lists of assigned workspace numbers is constructed.
- *
- * @returns An object where each key is a monitor name, and each value is an array of workspace numbers.
- */
-function getWorkspaceMonitorMap(): WorkspaceMonitorMap {
- try {
- const rulesResponse = hyprlandService.message('j/workspacerules');
- const workspaceMonitorRules: WorkspaceMonitorMap = {};
- const parsedWorkspaceRules = JSON.parse(rulesResponse);
-
- parsedWorkspaceRules.forEach((rule: WorkspaceRule) => {
- const workspaceNumber = parseInt(rule.workspaceString, 10);
-
- if (rule.monitor === undefined || isNaN(workspaceNumber)) {
- return;
- }
-
- const doesMonitorExistInRules = Object.hasOwnProperty.call(workspaceMonitorRules, rule.monitor);
-
- if (doesMonitorExistInRules) {
- workspaceMonitorRules[rule.monitor].push(workspaceNumber);
- } else {
- workspaceMonitorRules[rule.monitor] = [workspaceNumber];
- }
- });
-
- return workspaceMonitorRules;
- } catch (error) {
- console.error(error);
- return {};
- }
-}
-
-/**
- * Checks if a workspace number should be ignored based on a regular expression.
- *
- * @param ignoredWorkspacesVariable - A Variable object containing a string pattern of ignored workspaces.
- * @param workspaceNumber - The numeric representation of the workspace to check.
- *
- * @returns `true` if the workspace should be ignored, otherwise `false`.
- */
-function isWorkspaceIgnored(ignoredWorkspacesVariable: Variable, workspaceNumber: number): boolean {
- if (ignoredWorkspacesVariable.get() === '') {
- return false;
- }
-
- const ignoredWorkspacesRegex = new RegExp(ignoredWorkspacesVariable.get());
- return ignoredWorkspacesRegex.test(workspaceNumber.toString());
-}
-
-/**
- * Changes the active workspace in the specified direction ('next' or 'prev').
- *
- * This function uses the current monitor's set of active or assigned workspaces and
- * cycles through them in the chosen direction. It also respects the list of ignored
- * workspaces, skipping any that match the ignored pattern.
- *
- * @param direction - The direction to navigate ('next' or 'prev').
- * @param currentMonitorWorkspacesVariable - A Variable containing an array of workspace numbers for the current monitor.
- * @param onlyActiveWorkspaces - Whether to only include active (occupied) workspaces when navigating.
- * @param ignoredWorkspacesVariable - A Variable that contains the ignored workspaces pattern.
- */
-function navigateWorkspace(direction: 'next' | 'prev', ignoredWorkspacesVariable: Variable): void {
- const allHyprlandWorkspaces = hyprlandService.get_workspaces() ?? [];
-
- const activeWorkspaceIds = allHyprlandWorkspaces
- .filter((workspaceInstance) => hyprlandService.focusedMonitor.id === workspaceInstance.monitor?.id)
- .map((workspaceInstance) => workspaceInstance.id);
-
- const assignedOrOccupiedWorkspaces = activeWorkspaceIds.sort((a, b) => a - b);
-
- if (assignedOrOccupiedWorkspaces.length === 0) {
- return;
- }
-
- const workspaceIndex = assignedOrOccupiedWorkspaces.indexOf(hyprlandService.focusedWorkspace?.id);
- const step = direction === 'next' ? 1 : -1;
-
- let newIndex =
- (workspaceIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length;
- let attempts = 0;
-
- while (attempts < assignedOrOccupiedWorkspaces.length) {
- const targetWorkspaceNumber = assignedOrOccupiedWorkspaces[newIndex];
- if (!isWorkspaceIgnored(ignoredWorkspacesVariable, targetWorkspaceNumber)) {
- hyprlandService.dispatch('workspace', targetWorkspaceNumber.toString());
- return;
- }
- newIndex =
- (newIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length;
- attempts++;
- }
-}
-
-/**
- * Navigates to the next workspace in the current monitor.
- *
- * @param currentMonitorWorkspacesVariable - A Variable containing workspace numbers for the current monitor.
- * @param onlyActiveWorkspaces - Whether to only navigate among active (occupied) workspaces.
- * @param ignoredWorkspacesVariable - A Variable that contains the ignored workspaces pattern.
- */
-export function goToNextWorkspace(ignoredWorkspacesVariable: Variable): void {
- navigateWorkspace('next', ignoredWorkspacesVariable);
-}
-
-/**
- * Navigates to the previous workspace in the current monitor.
- *
- * @param currentMonitorWorkspacesVariable - A Variable containing workspace numbers for the current monitor.
- * @param onlyActiveWorkspaces - Whether to only navigate among active (occupied) workspaces.
- * @param ignoredWorkspacesVariable - A Variable that contains the ignored workspaces pattern.
- */
-export function goToPreviousWorkspace(ignoredWorkspacesVariable: Variable): void {
- navigateWorkspace('prev', ignoredWorkspacesVariable);
-}
-
-/**
- * Limits the execution rate of a given function to prevent it from being called too often.
- *
- * @param func - The function to be throttled.
- * @param limit - The time limit (in milliseconds) during which calls to `func` are disallowed after the first call.
- *
- * @returns The throttled version of the input function.
- */
-export function throttle void>(func: T, limit: number): T {
- let isThrottleActive: boolean;
-
- return function (this: ThisParameterType, ...args: Parameters) {
- if (!isThrottleActive) {
- func.apply(this, args);
- isThrottleActive = true;
-
- setTimeout(() => {
- isThrottleActive = false;
- }, limit);
- }
- } as T;
-}
-
-/**
- * Creates throttled scroll handlers that navigate workspaces upon scrolling, respecting the configured scroll speed.
- *
- * @param scrollSpeed - The factor by which the scroll navigation is throttled.
- * @param onlyActiveWorkspaces - Whether to only navigate among active (occupied) workspaces.
- *
- * @returns An object containing two functions (`throttledScrollUp` and `throttledScrollDown`), both throttled.
- */
-export function initThrottledScrollHandlers(scrollSpeed: number): ThrottledScrollHandlers {
- const throttledScrollUp = throttle(() => {
- if (reverse_scroll.get()) {
- goToPreviousWorkspace(ignored);
- } else {
- goToNextWorkspace(ignored);
- }
- }, 200 / scrollSpeed);
-
- const throttledScrollDown = throttle(() => {
- if (reverse_scroll.get()) {
- goToNextWorkspace(ignored);
- } else {
- goToPreviousWorkspace(ignored);
- }
- }, 200 / scrollSpeed);
-
- return { throttledScrollUp, throttledScrollDown };
-}
-
-/**
- * Computes which workspace numbers should be rendered for a given monitor.
- *
- * This function consolidates both active and all possible workspaces (based on rules),
- * then filters them by the selected monitor if `isMonitorSpecific` is set to `true`.
- *
- * @param totalWorkspaces - The total number of workspaces (a fallback if workspace rules are not enforced).
- * @param workspaceInstances - A list of Hyprland workspace objects.
- * @param workspaceMonitorRules - The map of monitor names to assigned workspace numbers.
- * @param monitorId - The numeric identifier of the monitor.
- * @param isMonitorSpecific - If `true`, only include the workspaces that match this monitor.
- * @param hyprlandMonitorInstances - A list of Hyprland monitor objects.
- *
- * @returns An array of workspace numbers that should be shown.
- */
-export function getWorkspacesToRender(
- totalWorkspaces: number,
- workspaceInstances: AstalHyprland.Workspace[],
- workspaceMonitorRules: WorkspaceMonitorMap,
- monitorId: number,
- isMonitorSpecific: boolean,
- hyprlandMonitorInstances: AstalHyprland.Monitor[],
-): number[] {
- let allPotentialWorkspaces = range(totalWorkspaces || 8);
- const allWorkspaceInstances = workspaceInstances ?? [];
-
- const activeWorkspaceIds = allWorkspaceInstances.map((workspaceInstance) => workspaceInstance.id);
-
- const monitorReferencesForActiveWorkspaces = allWorkspaceInstances.map((workspaceInstance) => {
- return {
- id: workspaceInstance.monitor?.id ?? -1,
- name: workspaceInstance.monitor?.name ?? '',
- };
- });
-
- const currentMonitorInstance =
- hyprlandMonitorInstances.find((monitorObj) => monitorObj.id === monitorId) ||
- monitorReferencesForActiveWorkspaces.find((monitorObj) => monitorObj.id === monitorId);
-
- const allWorkspacesWithRules = Object.keys(workspaceMonitorRules).reduce(
- (accumulator: number[], monitorName: string) => {
- return [...accumulator, ...workspaceMonitorRules[monitorName]];
- },
- [],
- );
-
- const activeWorkspacesForCurrentMonitor = activeWorkspaceIds.filter((workspaceId) => {
- const metadataForWorkspace = allWorkspaceInstances.find(
- (workspaceObj) => workspaceObj.id === workspaceId,
- );
-
- if (metadataForWorkspace) {
- return metadataForWorkspace?.monitor?.id === monitorId;
- }
-
- if (
- currentMonitorInstance &&
- Object.hasOwnProperty.call(workspaceMonitorRules, currentMonitorInstance.name) &&
- allWorkspacesWithRules.includes(workspaceId)
- ) {
- return workspaceMonitorRules[currentMonitorInstance.name].includes(workspaceId);
- }
-
- return false;
- });
-
- if (isMonitorSpecific) {
- const validWorkspaceNumbers = range(totalWorkspaces).filter((workspaceNumber) => {
- return isWorkspaceValidForMonitor(
- workspaceNumber,
- workspaceMonitorRules,
- monitorId,
- allWorkspaceInstances,
- hyprlandMonitorInstances,
- );
- });
-
- allPotentialWorkspaces = [
- ...new Set([...activeWorkspacesForCurrentMonitor, ...validWorkspaceNumbers]),
- ];
- } else {
- allPotentialWorkspaces = [...new Set([...allPotentialWorkspaces, ...activeWorkspaceIds])];
- }
-
- return allPotentialWorkspaces
- .filter((workspace) => !isWorkspaceIgnored(ignored, workspace))
- .sort((a, b) => a - b);
-}
-
-/**
- * Subscribes to Hyprland service events related to workspaces to keep the local state updated.
- *
- * When certain events occur (like a configuration reload or a client being moved/added/removed),
- * this function updates the workspace rules or toggles the `forceUpdater` variable to ensure
- * that any dependent UI or logic is re-rendered or re-run.
- */
-export function initWorkspaceEvents(): void {
- hyprlandService.connect('config-reloaded', () => {
- workspaceRules.set(getWorkspaceMonitorMap());
- });
-
- hyprlandService.connect('client-moved', () => {
- forceUpdater.set(!forceUpdater.get());
- });
-
- hyprlandService.connect('client-added', () => {
- forceUpdater.set(!forceUpdater.get());
- });
-
- hyprlandService.connect('client-removed', () => {
- forceUpdater.set(!forceUpdater.get());
- });
-}
-
-/**
- * Throttled scroll handler functions for navigating workspaces.
- */
-type ThrottledScrollHandlers = {
- /**
- * Scroll up throttled handler.
- */
- throttledScrollUp: () => void;
-
- /**
- * Scroll down throttled handler.
- */
- throttledScrollDown: () => void;
+const isWorkspaceActiveOnMonitor = (monitor: number, i: number): boolean => {
+ return showAllActive.get() && hyprlandService.get_monitor(monitor)?.activeWorkspace?.id === i;
+};
+
+/**
+ * Retrieves the icon for a given workspace.
+ *
+ * This function returns the icon associated with a workspace from the provided workspace icon map.
+ * If no icon is found, it returns the workspace index as a string.
+ *
+ * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icons or icon objects.
+ * @param i The index of the workspace for which to retrieve the icon.
+ *
+ * @returns The icon for the workspace as a string. If no icon is found, returns the workspace index as a string.
+ */
+const getWsIcon = (wsIconMap: WorkspaceIconMap, i: number): string => {
+ const iconEntry = wsIconMap[i];
+ const defaultIcon = `${i}`;
+
+ if (iconEntry === undefined) {
+ return defaultIcon;
+ }
+
+ if (typeof iconEntry === 'string' && iconEntry !== '') {
+ return iconEntry;
+ }
+
+ const hasIcon = typeof iconEntry === 'object' && 'icon' in iconEntry && iconEntry.icon !== '';
+
+ if (hasIcon) {
+ return iconEntry.icon;
+ }
+
+ return defaultIcon;
+};
+
+/**
+ * Retrieves the color for a given workspace.
+ *
+ * This function determines the color styling for a workspace based on the provided workspace icon map,
+ * smart highlighting settings, and the monitor index. It returns a CSS string for the color and background.
+ *
+ * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icon objects.
+ * @param i The index of the workspace for which to retrieve the color.
+ * @param smartHighlight A boolean indicating whether smart highlighting is enabled.
+ * @param monitor The index of the monitor to check for active workspaces.
+ *
+ * @returns A CSS string representing the color and background for the workspace. If no color is found, returns an empty string.
+ */
+export const getWsColor = (
+ wsIconMap: WorkspaceIconMap,
+ i: number,
+ smartHighlight: boolean,
+ monitor: number,
+): string => {
+ const iconEntry = wsIconMap[i];
+ const hasColor =
+ typeof iconEntry === 'object' && 'color' in iconEntry && isValidGjsColor(iconEntry.color);
+
+ if (iconEntry === undefined) {
+ return '';
+ }
+
+ if (
+ showWsIcons.get() &&
+ smartHighlight &&
+ wsActiveIndicator.get() === 'highlight' &&
+ (hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i))
+ ) {
+ const iconColor = monochrome.get() ? background.get() : wsBackground.get();
+ const iconBackground = hasColor && isValidGjsColor(iconEntry.color) ? iconEntry.color : active.get();
+ const colorCss = `color: ${iconColor};`;
+ const backgroundCss = `background: ${iconBackground};`;
+
+ return colorCss + backgroundCss;
+ }
+
+ if (hasColor && isValidGjsColor(iconEntry.color)) {
+ return `color: ${iconEntry.color}; border-bottom-color: ${iconEntry.color};`;
+ }
+
+ return '';
+};
+
+/**
+ * Retrieves the application icon for a given workspace.
+ *
+ * This function returns the appropriate application icon for the specified workspace index.
+ * It considers user-defined icons, default icons, and the option to remove duplicate icons.
+ *
+ * @param workspaceIndex The index of the workspace for which to retrieve the application icon.
+ * @param removeDuplicateIcons A boolean indicating whether to remove duplicate icons.
+ * @param options An object containing user-defined icon map, default icon, and empty icon.
+ *
+ * @returns The application icon for the workspace as a string. If no icons are found, returns the default or empty icon.
+ */
+export const getAppIcon = (
+ workspaceIndex: number,
+ removeDuplicateIcons: boolean,
+ { iconMap: userDefinedIconMap, defaultIcon, emptyIcon }: AppIconOptions,
+): string => {
+ const workspaceClients = hyprlandService
+ .get_clients()
+ .filter((client) => client?.workspace?.id === workspaceIndex)
+ .map((client) => [client.class, client.title]);
+
+ if (!workspaceClients.length) {
+ return emptyIcon;
+ }
+
+ const findIconForClient = (clientClass: string, clientTitle: string): string | undefined => {
+ const appIconMap = { ...userDefinedIconMap, ...defaultApplicationIconMap };
+
+ const iconEntry = Object.entries(appIconMap).find(([matcher]) => {
+ if (matcher.startsWith('class:')) {
+ return new RegExp(matcher.substring(6)).test(clientClass);
+ }
+
+ if (matcher.startsWith('title:')) {
+ return new RegExp(matcher.substring(6)).test(clientTitle);
+ }
+
+ return new RegExp(matcher, 'i').test(clientClass);
+ });
+
+ return iconEntry?.[1] ?? defaultIcon;
+ };
+
+ let icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => {
+ const icon = findIconForClient(clientClass, clientTitle);
+
+ if (icon !== undefined) {
+ iconAccumulator.push(icon);
+ }
+
+ return iconAccumulator;
+ }, []);
+
+ if (icons.length) {
+ if (removeDuplicateIcons) {
+ icons = unique(icons);
+ }
+
+ return icons.join(' ');
+ }
+
+ return defaultIcon;
+};
+
+/**
+ * Renders the class names for a workspace.
+ *
+ * This function generates the appropriate class names for a workspace based on various settings such as
+ * whether to show icons, numbered workspaces, workspace icons, and smart highlighting.
+ *
+ * @param showIcons A boolean indicating whether to show icons.
+ * @param showNumbered A boolean indicating whether to show numbered workspaces.
+ * @param numberedActiveIndicator The indicator for active numbered workspaces.
+ * @param showWsIcons A boolean indicating whether to show workspace icons.
+ * @param smartHighlight A boolean indicating whether smart highlighting is enabled.
+ * @param monitor The index of the monitor to check for active workspaces.
+ * @param i The index of the workspace for which to render class names.
+ *
+ * @returns The class names for the workspace as a string.
+ */
+export const renderClassnames = (
+ showIcons: boolean,
+ showNumbered: boolean,
+ numberedActiveIndicator: string,
+ showWsIcons: boolean,
+ smartHighlight: boolean,
+ monitor: number,
+ i: number,
+): string => {
+ const isWorkspaceActive =
+ hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i);
+ const isActive = isWorkspaceActive ? 'active' : '';
+
+ if (showIcons) {
+ return `workspace-icon txt-icon bar ${isActive}`;
+ }
+
+ if (showNumbered || showWsIcons) {
+ const numActiveInd = isWorkspaceActive ? numberedActiveIndicator : '';
+
+ const wsIconClass = showWsIcons ? 'txt-icon' : '';
+ const smartHighlightClass = smartHighlight ? 'smart-highlight' : '';
+
+ const className = `workspace-number can_${numberedActiveIndicator} ${numActiveInd} ${wsIconClass} ${smartHighlightClass} ${isActive}`;
+
+ return className.trim();
+ }
+
+ return `default ${isActive}`;
+};
+
+/**
+ * Renders the label for a workspace.
+ *
+ * This function generates the appropriate label for a workspace based on various settings such as
+ * whether to show icons, application icons, workspace icons, and workspace indicators.
+ *
+ * @param showIcons A boolean indicating whether to show icons.
+ * @param availableIndicator The indicator for available workspaces.
+ * @param activeIndicator The indicator for active workspaces.
+ * @param occupiedIndicator The indicator for occupied workspaces.
+ * @param showAppIcons A boolean indicating whether to show application icons.
+ * @param appIcons The application icons as a string.
+ * @param workspaceMask A boolean indicating whether to mask the workspace.
+ * @param showWorkspaceIcons A boolean indicating whether to show workspace icons.
+ * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icons or icon objects.
+ * @param i The index of the workspace for which to render the label.
+ * @param index The index of the workspace in the list.
+ * @param monitor The index of the monitor to check for active workspaces.
+ *
+ * @returns The label for the workspace as a string.
+ */
+export const renderLabel = (
+ showIcons: boolean,
+ availableIndicator: string,
+ activeIndicator: string,
+ occupiedIndicator: string,
+ showAppIcons: boolean,
+ appIcons: string,
+ workspaceMask: boolean,
+ showWorkspaceIcons: boolean,
+ wsIconMap: WorkspaceIconMap,
+ i: number,
+ index: number,
+ monitor: number,
+): string => {
+ if (showAppIcons) {
+ return appIcons;
+ }
+
+ if (showIcons) {
+ if (hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i)) {
+ return activeIndicator;
+ }
+ if ((hyprlandService.get_workspace(i)?.get_clients().length || 0) > 0) {
+ return occupiedIndicator;
+ }
+ if (monitor !== -1) {
+ return availableIndicator;
+ }
+ }
+
+ if (showWorkspaceIcons) {
+ return getWsIcon(wsIconMap, i);
+ }
+
+ return workspaceMask ? `${index + 1}` : `${i}`;
};
diff --git a/src/components/bar/modules/workspaces/helpers/types.ts b/src/components/bar/modules/workspaces/helpers/types.ts
new file mode 100644
index 0000000..01d2694
--- /dev/null
+++ b/src/components/bar/modules/workspaces/helpers/types.ts
@@ -0,0 +1,7 @@
+import { ApplicationIcons } from '../types';
+
+export type AppIconOptions = {
+ iconMap: ApplicationIcons;
+ defaultIcon: string;
+ emptyIcon: string;
+};
diff --git a/src/components/bar/modules/workspaces/helpers/utils.ts b/src/components/bar/modules/workspaces/helpers/utils.ts
index cc1773e..f09196f 100644
--- a/src/components/bar/modules/workspaces/helpers/utils.ts
+++ b/src/components/bar/modules/workspaces/helpers/utils.ts
@@ -1,276 +1,99 @@
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
-import { defaultApplicationIconMap } from 'src/lib/constants/appIcons';
-import { WorkspaceIconMap, AppIconOptions } from 'src/lib/types/workspace.types';
-import { isValidGjsColor } from 'src/lib/utils';
-import options from 'src/options';
+import options from 'src/configuration';
+import { WorkspaceService } from 'src/services/workspace';
+
+const workspaceService = WorkspaceService.getInstance();
const hyprlandService = AstalHyprland.get_default();
-const { monochrome, background } = options.theme.bar.buttons;
-const { background: wsBackground, active } = options.theme.bar.buttons.workspaces;
-
-const { showWsIcons, showAllActive, numbered_active_indicator: wsActiveIndicator } = options.bar.workspaces;
+const { reverse_scroll } = options.bar.workspaces;
/**
- * Determines if a workspace is active on a given monitor.
+ * Limits the execution rate of a given function to prevent it from being called too often.
*
- * This function checks if the workspace with the specified index is currently active on the given monitor.
- * It uses the `showAllActive` setting and the `hyprlandService` to determine the active workspace on the monitor.
+ * @param func - The function to be throttled.
+ * @param limit - The time limit (in milliseconds) during which calls to `func` are disallowed after the first call.
*
- * @param monitor The index of the monitor to check.
- * @param i The index of the workspace to check.
- *
- * @returns True if the workspace is active on the monitor, false otherwise.
+ * @returns The throttled version of the input function.
*/
-const isWorkspaceActiveOnMonitor = (monitor: number, i: number): boolean => {
- return showAllActive.get() && hyprlandService.get_monitor(monitor)?.activeWorkspace?.id === i;
-};
+function throttle void>(func: T, limit: number): T {
+ let isThrottleActive: boolean;
-/**
- * Retrieves the icon for a given workspace.
- *
- * This function returns the icon associated with a workspace from the provided workspace icon map.
- * If no icon is found, it returns the workspace index as a string.
- *
- * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icons or icon objects.
- * @param i The index of the workspace for which to retrieve the icon.
- *
- * @returns The icon for the workspace as a string. If no icon is found, returns the workspace index as a string.
- */
-const getWsIcon = (wsIconMap: WorkspaceIconMap, i: number): string => {
- const iconEntry = wsIconMap[i];
- const defaultIcon = `${i}`;
+ return function (this: ThisParameterType, ...args: Parameters) {
+ if (!isThrottleActive) {
+ func.apply(this, args);
+ isThrottleActive = true;
- if (iconEntry === undefined) {
- return defaultIcon;
- }
-
- if (typeof iconEntry === 'string' && iconEntry !== '') {
- return iconEntry;
- }
-
- const hasIcon = typeof iconEntry === 'object' && 'icon' in iconEntry && iconEntry.icon !== '';
-
- if (hasIcon) {
- return iconEntry.icon;
- }
-
- return defaultIcon;
-};
-
-/**
- * Retrieves the color for a given workspace.
- *
- * This function determines the color styling for a workspace based on the provided workspace icon map,
- * smart highlighting settings, and the monitor index. It returns a CSS string for the color and background.
- *
- * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icon objects.
- * @param i The index of the workspace for which to retrieve the color.
- * @param smartHighlight A boolean indicating whether smart highlighting is enabled.
- * @param monitor The index of the monitor to check for active workspaces.
- *
- * @returns A CSS string representing the color and background for the workspace. If no color is found, returns an empty string.
- */
-export const getWsColor = (
- wsIconMap: WorkspaceIconMap,
- i: number,
- smartHighlight: boolean,
- monitor: number,
-): string => {
- const iconEntry = wsIconMap[i];
- const hasColor =
- typeof iconEntry === 'object' && 'color' in iconEntry && isValidGjsColor(iconEntry.color);
-
- if (iconEntry === undefined) {
- return '';
- }
-
- if (
- showWsIcons.get() &&
- smartHighlight &&
- wsActiveIndicator.get() === 'highlight' &&
- (hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i))
- ) {
- const iconColor = monochrome.get() ? background.get() : wsBackground.get();
- const iconBackground = hasColor && isValidGjsColor(iconEntry.color) ? iconEntry.color : active.get();
- const colorCss = `color: ${iconColor};`;
- const backgroundCss = `background: ${iconBackground};`;
-
- return colorCss + backgroundCss;
- }
-
- if (hasColor && isValidGjsColor(iconEntry.color)) {
- return `color: ${iconEntry.color}; border-bottom-color: ${iconEntry.color};`;
- }
-
- return '';
-};
-
-/**
- * Retrieves the application icon for a given workspace.
- *
- * This function returns the appropriate application icon for the specified workspace index.
- * It considers user-defined icons, default icons, and the option to remove duplicate icons.
- *
- * @param workspaceIndex The index of the workspace for which to retrieve the application icon.
- * @param removeDuplicateIcons A boolean indicating whether to remove duplicate icons.
- * @param options An object containing user-defined icon map, default icon, and empty icon.
- *
- * @returns The application icon for the workspace as a string. If no icons are found, returns the default or empty icon.
- */
-export const getAppIcon = (
- workspaceIndex: number,
- removeDuplicateIcons: boolean,
- { iconMap: userDefinedIconMap, defaultIcon, emptyIcon }: AppIconOptions,
-): string => {
- const workspaceClients = hyprlandService
- .get_clients()
- .filter((client) => client?.workspace?.id === workspaceIndex)
- .map((client) => [client.class, client.title]);
-
- if (!workspaceClients.length) {
- return emptyIcon;
- }
-
- const findIconForClient = (clientClass: string, clientTitle: string): string | undefined => {
- const appIconMap = { ...userDefinedIconMap, ...defaultApplicationIconMap };
-
- const iconEntry = Object.entries(appIconMap).find(([matcher]) => {
- if (matcher.startsWith('class:')) {
- return new RegExp(matcher.substring(6)).test(clientClass);
- }
-
- if (matcher.startsWith('title:')) {
- return new RegExp(matcher.substring(6)).test(clientTitle);
- }
-
- return new RegExp(matcher, 'i').test(clientClass);
- });
-
- return iconEntry?.[1] ?? defaultIcon;
- };
-
- let icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => {
- const icon = findIconForClient(clientClass, clientTitle);
-
- if (icon !== undefined) {
- iconAccumulator.push(icon);
+ setTimeout(() => {
+ isThrottleActive = false;
+ }, limit);
}
-
- return iconAccumulator;
- }, []);
-
- if (icons.length) {
- if (removeDuplicateIcons) {
- icons = [...new Set(icons)];
- }
-
- return icons.join(' ');
- }
-
- return defaultIcon;
-};
+ } as T;
+}
/**
- * Renders the class names for a workspace.
+ * Creates throttled scroll handlers that navigate workspaces upon scrolling, respecting the configured scroll speed.
*
- * This function generates the appropriate class names for a workspace based on various settings such as
- * whether to show icons, numbered workspaces, workspace icons, and smart highlighting.
+ * @param scrollSpeed - The factor by which the scroll navigation is throttled.
+ * @param onlyActiveWorkspaces - Whether to only navigate among active (occupied) workspaces.
*
- * @param showIcons A boolean indicating whether to show icons.
- * @param showNumbered A boolean indicating whether to show numbered workspaces.
- * @param numberedActiveIndicator The indicator for active numbered workspaces.
- * @param showWsIcons A boolean indicating whether to show workspace icons.
- * @param smartHighlight A boolean indicating whether smart highlighting is enabled.
- * @param monitor The index of the monitor to check for active workspaces.
- * @param i The index of the workspace for which to render class names.
- *
- * @returns The class names for the workspace as a string.
+ * @returns An object containing two functions (`throttledScrollUp` and `throttledScrollDown`), both throttled.
*/
-export const renderClassnames = (
- showIcons: boolean,
- showNumbered: boolean,
- numberedActiveIndicator: string,
- showWsIcons: boolean,
- smartHighlight: boolean,
- monitor: number,
- i: number,
-): string => {
- const isWorkspaceActive =
- hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i);
- const isActive = isWorkspaceActive ? 'active' : '';
+export function initThrottledScrollHandlers(scrollSpeed: number): ThrottledScrollHandlers {
+ const throttledScrollUp = throttle(() => {
+ if (reverse_scroll.get()) {
+ workspaceService.goToPreviousWorkspace();
+ } else {
+ workspaceService.goToNextWorkspace();
+ }
+ }, 200 / scrollSpeed);
- if (showIcons) {
- return `workspace-icon txt-icon bar ${isActive}`;
- }
+ const throttledScrollDown = throttle(() => {
+ if (reverse_scroll.get()) {
+ workspaceService.goToNextWorkspace();
+ } else {
+ workspaceService.goToPreviousWorkspace();
+ }
+ }, 200 / scrollSpeed);
- if (showNumbered || showWsIcons) {
- const numActiveInd = isWorkspaceActive ? numberedActiveIndicator : '';
-
- const wsIconClass = showWsIcons ? 'txt-icon' : '';
- const smartHighlightClass = smartHighlight ? 'smart-highlight' : '';
-
- const className = `workspace-number can_${numberedActiveIndicator} ${numActiveInd} ${wsIconClass} ${smartHighlightClass} ${isActive}`;
-
- return className.trim();
- }
-
- return `default ${isActive}`;
-};
+ return { throttledScrollUp, throttledScrollDown };
+}
/**
- * Renders the label for a workspace.
+ * Subscribes to Hyprland service events related to workspaces to keep the local state updated.
*
- * This function generates the appropriate label for a workspace based on various settings such as
- * whether to show icons, application icons, workspace icons, and workspace indicators.
- *
- * @param showIcons A boolean indicating whether to show icons.
- * @param availableIndicator The indicator for available workspaces.
- * @param activeIndicator The indicator for active workspaces.
- * @param occupiedIndicator The indicator for occupied workspaces.
- * @param showAppIcons A boolean indicating whether to show application icons.
- * @param appIcons The application icons as a string.
- * @param workspaceMask A boolean indicating whether to mask the workspace.
- * @param showWorkspaceIcons A boolean indicating whether to show workspace icons.
- * @param wsIconMap The map of workspace icons where keys are workspace indices and values are icons or icon objects.
- * @param i The index of the workspace for which to render the label.
- * @param index The index of the workspace in the list.
- * @param monitor The index of the monitor to check for active workspaces.
- *
- * @returns The label for the workspace as a string.
+ * When certain events occur (like a configuration reload or a client being moved/added/removed),
+ * this function updates the workspace rules or toggles the `forceUpdater` variable to ensure
+ * that any dependent UI or logic is re-rendered or re-run.
*/
-export const renderLabel = (
- showIcons: boolean,
- availableIndicator: string,
- activeIndicator: string,
- occupiedIndicator: string,
- showAppIcons: boolean,
- appIcons: string,
- workspaceMask: boolean,
- showWorkspaceIcons: boolean,
- wsIconMap: WorkspaceIconMap,
- i: number,
- index: number,
- monitor: number,
-): string => {
- if (showAppIcons) {
- return appIcons;
- }
+export function initWorkspaceEvents(): void {
+ hyprlandService.connect('config-reloaded', () => {
+ workspaceService.refreshWorkspaceRules();
+ });
- if (showIcons) {
- if (hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i)) {
- return activeIndicator;
- }
- if ((hyprlandService.get_workspace(i)?.get_clients().length || 0) > 0) {
- return occupiedIndicator;
- }
- if (monitor !== -1) {
- return availableIndicator;
- }
- }
+ hyprlandService.connect('client-moved', () => {
+ workspaceService.forceAnUpdate();
+ });
- if (showWorkspaceIcons) {
- return getWsIcon(wsIconMap, i);
- }
+ hyprlandService.connect('client-added', () => {
+ workspaceService.forceAnUpdate();
+ });
- return workspaceMask ? `${index + 1}` : `${i}`;
+ hyprlandService.connect('client-removed', () => {
+ workspaceService.forceAnUpdate();
+ });
+}
+
+/**
+ * Throttled scroll handler functions for navigating workspaces.
+ */
+type ThrottledScrollHandlers = {
+ /**
+ * Scroll up throttled handler.
+ */
+ throttledScrollUp: () => void;
+
+ /**
+ * Scroll down throttled handler.
+ */
+ throttledScrollDown: () => void;
};
diff --git a/src/components/bar/modules/workspaces/index.tsx b/src/components/bar/modules/workspaces/index.tsx
index bf33a1c..0d83e0b 100644
--- a/src/components/bar/modules/workspaces/index.tsx
+++ b/src/components/bar/modules/workspaces/index.tsx
@@ -1,11 +1,10 @@
-import options from 'src/options';
-import { initThrottledScrollHandlers } from './helpers';
+import { initThrottledScrollHandlers } from './helpers/utils';
import { WorkspaceModule } from './workspaces';
import { bind, Variable } from 'astal';
import { Astal, Gdk } from 'astal/gtk3';
-import { isScrollDown, isScrollUp } from 'src/lib/utils';
-import { BarBoxChild } from 'src/lib/types/bar.types';
-import { GtkWidget } from 'src/lib/types/widget.types';
+import options from 'src/configuration';
+import { isScrollUp, isScrollDown } from 'src/lib/events/mouse';
+import { BarBoxChild, GtkWidget } from 'src/components/bar/types';
const { scroll_speed } = options.bar.workspaces;
diff --git a/src/components/bar/modules/workspaces/types.ts b/src/components/bar/modules/workspaces/types.ts
new file mode 100644
index 0000000..b52badd
--- /dev/null
+++ b/src/components/bar/modules/workspaces/types.ts
@@ -0,0 +1,15 @@
+export type WorkspaceIcons = {
+ [key: string]: string;
+};
+
+export type WorkspaceIconsColored = {
+ [key: string]: {
+ color: string;
+ icon: string;
+ };
+};
+export type ApplicationIcons = {
+ [key: string]: string;
+};
+
+export type WorkspaceIconMap = WorkspaceIcons | WorkspaceIconsColored;
diff --git a/src/components/bar/modules/workspaces/workspaces.tsx b/src/components/bar/modules/workspaces/workspaces.tsx
index 8be5a2c..8b1fe17 100644
--- a/src/components/bar/modules/workspaces/workspaces.tsx
+++ b/src/components/bar/modules/workspaces/workspaces.tsx
@@ -1,11 +1,14 @@
-import options from 'src/options';
-import { forceUpdater, getWorkspacesToRender, initWorkspaceEvents, workspaceRules } from './helpers';
-import { getAppIcon, getWsColor, renderClassnames, renderLabel } from './helpers/utils';
+import { initWorkspaceEvents } from './helpers/utils';
+import { getAppIcon, getWsColor, renderClassnames, renderLabel } from './helpers';
import { bind, Variable } from 'astal';
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { Gtk } from 'astal/gtk3';
-import { isPrimaryClick } from 'src/lib/utils';
-import { WorkspaceIconMap, ApplicationIcons } from 'src/lib/types/workspace.types';
+import { WorkspaceService } from 'src/services/workspace';
+import options from 'src/configuration';
+import { isPrimaryClick } from 'src/lib/events/mouse';
+import { WorkspaceIconMap, ApplicationIcons } from './types';
+
+const workspaceService = WorkspaceService.getInstance();
const hyprlandService = AstalHyprland.get_default();
const {
@@ -61,8 +64,8 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
bind(ignored),
bind(showAllActive),
bind(hyprlandService, 'focusedWorkspace'),
- bind(workspaceRules),
- bind(forceUpdater),
+ bind(workspaceService.workspaceRules),
+ bind(workspaceService.forceUpdater),
],
(
isMonitorSpecific: boolean,
@@ -88,10 +91,11 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
clients: AstalHyprland.Client[],
monitorList: AstalHyprland.Monitor[],
) => {
- const workspacesToRender = getWorkspacesToRender(
+ const wsRules = workspaceService.workspaceRules.get();
+ const workspacesToRender = workspaceService.getWorkspaces(
totalWorkspaces,
workspaceList,
- workspaceRules.get(),
+ wsRules,
monitor,
isMonitorSpecific,
monitorList,
diff --git a/src/components/bar/modules/worldclock/index.tsx b/src/components/bar/modules/worldclock/index.tsx
index 8693108..ae0cd51 100644
--- a/src/components/bar/modules/worldclock/index.tsx
+++ b/src/components/bar/modules/worldclock/index.tsx
@@ -1,11 +1,13 @@
-import options from 'src/options';
-import { inputHandler } from 'src/components/bar/utils/helpers.js';
import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3';
-import { systemTime } from 'src/shared/time';
+import { systemTime } from 'src/lib/units/time';
import { GLib } from 'astal';
-import { Module } from '../../shared/Module';
-import { BarBoxChild } from 'src/lib/types/bar.types';
+import { Module } from '../../shared/module';
+import { BarBoxChild } from 'src/components/bar/types';
+import options from 'src/configuration';
+import { InputHandlerService } from '../../utils/input/inputHandler';
+
+const inputHandler = InputHandlerService.getInstance();
const {
format,
@@ -51,13 +53,15 @@ export const WorldClock = (): BarBoxChild => {
.join(timeDivider),
);
+ let inputHandlerBindings: Variable;
+
const microphoneModule = Module({
textIcon: iconBinding(),
label: timeBinding(),
boxClass: 'worldclock',
props: {
setup: (self: Astal.Button) => {
- inputHandler(self, {
+ inputHandlerBindings = inputHandler.attachHandlers(self, {
onPrimaryClick: {
cmd: leftClick,
},
@@ -75,6 +79,11 @@ export const WorldClock = (): BarBoxChild => {
},
});
},
+ onDestroy: () => {
+ inputHandlerBindings.drop();
+ timeBinding.drop();
+ iconBinding.drop();
+ },
},
});
diff --git a/src/components/bar/settings/config.tsx b/src/components/bar/settings/config.tsx
index 35bfd1b..9f9d036 100644
--- a/src/components/bar/settings/config.tsx
+++ b/src/components/bar/settings/config.tsx
@@ -1,7 +1,7 @@
import { Option } from 'src/components/settings/shared/Option';
import { Header } from 'src/components/settings/shared/Header';
-import options from 'src/options';
import { Gtk } from 'astal/gtk3';
+import options from 'src/configuration';
export const CustomModuleSettings = (): JSX.Element => {
return (
@@ -176,6 +176,12 @@ export const CustomModuleSettings = (): JSX.Element => {
{/* Storage Section */}
+
+