F: Replace react-select with shadcn based analogue

This commit is contained in:
Ivan 2025-04-13 17:17:25 +03:00
parent efd143ae94
commit 873a26483c
15 changed files with 219 additions and 433 deletions

View File

@ -35,7 +35,6 @@ This readme file is used mostly to document project dependencies and conventions
- react-toastify - react-toastify
- react-tabs - react-tabs
- react-intl - react-intl
- react-select
- react-error-boundary - react-error-boundary
- react-tooltip - react-tooltip
- react-zoom-pan-pinch - react-zoom-pan-pinch

View File

@ -31,11 +31,9 @@ User profile:
- Sitemap for better SEO and crawler optimization - Sitemap for better SEO and crawler optimization
[Functionality - CANCELED] [Functionality - CANCELED]
- User notifications on edit - consider spam prevention and change aggregation
- Integrate socials and feedback - Integrate socials and feedback
- Content based search in Library - Content based search in Library
- Private projects. Consider cooperative editing - Private projects. Consider cooperative editing
- OSS: synthesis table: auto substitution for diamond synthesis
[Tech] [Tech]

View File

@ -34,7 +34,6 @@
"react-intl": "^7.1.10", "react-intl": "^7.1.10",
"react-router": "^7.5.0", "react-router": "^7.5.0",
"react-scan": "^0.3.3", "react-scan": "^0.3.3",
"react-select": "^5.10.1",
"react-tabs": "^6.1.0", "react-tabs": "^6.1.0",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"react-tooltip": "^5.28.1", "react-tooltip": "^5.28.1",
@ -987,135 +986,6 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"license": "MIT"
},
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@emotion/cache": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"license": "MIT"
},
"node_modules/@emotion/react": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"license": "MIT"
},
"node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"license": "MIT"
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2", "version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
@ -4434,7 +4304,10 @@
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"license": "MIT" "dev": true,
"license": "MIT",
"optional": true,
"peer": true
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.1.1", "version": "19.1.1",
@ -4464,15 +4337,6 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@types/stack-utils": { "node_modules/@types/stack-utils": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
@ -5211,7 +5075,10 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0", "cosmiconfig": "^7.0.0",
@ -5500,6 +5367,7 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@ -5747,7 +5615,10 @@
"version": "7.1.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"@types/parse-json": "^4.0.0", "@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
@ -5763,7 +5634,10 @@
"version": "1.10.2", "version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"license": "ISC", "license": "ISC",
"optional": true,
"peer": true,
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
} }
@ -6175,16 +6049,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dom-walk": { "node_modules/dom-walk": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
@ -6274,6 +6138,7 @@
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"is-arrayish": "^0.2.1" "is-arrayish": "^0.2.1"
@ -6502,6 +6367,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
@ -7240,12 +7106,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -7903,6 +7763,7 @@
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"parent-module": "^1.0.0", "parent-module": "^1.0.0",
@ -8020,6 +7881,7 @@
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/is-async-function": { "node_modules/is-async-function": {
@ -8092,6 +7954,7 @@
"version": "2.16.1", "version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"hasown": "^2.0.2" "hasown": "^2.0.2"
@ -9211,6 +9074,7 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
@ -9559,6 +9423,7 @@
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/locate-path": { "node_modules/locate-path": {
@ -9688,12 +9553,6 @@
"dev": true, "dev": true,
"license": "CC0-1.0" "license": "CC0-1.0"
}, },
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/meow": { "node_modules/meow": {
"version": "13.2.0", "version": "13.2.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
@ -10110,6 +9969,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"callsites": "^3.0.0" "callsites": "^3.0.0"
@ -10122,6 +9982,7 @@
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.0.0", "@babel/code-frame": "^7.0.0",
@ -10170,12 +10031,14 @@
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -10816,27 +10679,6 @@
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-select": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.1.tgz",
"integrity": "sha512-roPEZUL4aRZDx6DcsD+ZNreVl+fM8VsKn0Wtex1v4IazH60ILp5xhdlp464IsEAlJdXeD+BhDAFsBVMfvLQueA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.0",
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.8.1",
"@floating-ui/dom": "^1.0.1",
"@types/react-transition-group": "^4.4.0",
"memoize-one": "^6.0.0",
"prop-types": "^15.6.0",
"react-transition-group": "^4.3.0",
"use-isomorphic-layout-effect": "^1.2.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-style-singleton": { "node_modules/react-style-singleton": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
@ -10899,22 +10741,6 @@
"react-dom": ">=16.14.0" "react-dom": ">=16.14.0"
} }
}, },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"license": "BSD-3-Clause",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/react-zoom-pan-pinch": { "node_modules/react-zoom-pan-pinch": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz", "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz",
@ -11021,6 +10847,7 @@
"version": "1.22.10", "version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"is-core-module": "^2.16.0", "is-core-module": "^2.16.0",
@ -11064,6 +10891,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
@ -11898,12 +11726,6 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0" "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
} }
}, },
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -11938,6 +11760,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -12935,20 +12758,6 @@
"react": "*" "react": "*"
} }
}, },
"node_modules/use-isomorphic-layout-effect": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz",
"integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": { "node_modules/use-sidecar": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",

View File

@ -40,7 +40,6 @@
"react-intl": "^7.1.10", "react-intl": "^7.1.10",
"react-router": "^7.5.0", "react-router": "^7.5.0",
"react-scan": "^0.3.3", "react-scan": "^0.3.3",
"react-select": "^5.10.1",
"react-tabs": "^6.1.0", "react-tabs": "^6.1.0",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"react-tooltip": "^5.28.1", "react-tooltip": "^5.28.1",

View File

@ -4,7 +4,6 @@ export { ErrorField } from './error-field';
export { FileInput } from './file-input'; export { FileInput } from './file-input';
export { Label } from './label'; export { Label } from './label';
export { SearchBar } from './search-bar'; export { SearchBar } from './search-bar';
export { SelectMulti, type SelectMultiProps } from './select-multi';
export { SelectTree } from './select-tree'; export { SelectTree } from './select-tree';
export { TextArea } from './text-area'; export { TextArea } from './text-area';
export { TextInput } from './text-input'; export { TextInput } from './text-input';

View File

@ -1,128 +0,0 @@
'use client';
import Select, {
type ClearIndicatorProps,
components,
type DropdownIndicatorProps,
type GroupBase,
type Props,
type StylesConfig
} from 'react-select';
import { useWindowSize } from '@/hooks/use-window-size';
import { APP_COLORS, SELECT_THEME } from '@/styling/colors';
import { IconClose, IconDropArrow, IconDropArrowUp } from '../icons';
function DropdownIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
props: DropdownIndicatorProps<Option, true, Group>
) {
return (
components.DropdownIndicator && (
<components.DropdownIndicator {...props}>
{props.selectProps.menuIsOpen ? <IconDropArrowUp size='1.25rem' /> : <IconDropArrow size='1.25rem' />}
</components.DropdownIndicator>
)
);
}
function ClearIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
props: ClearIndicatorProps<Option, true, Group>
) {
return (
components.ClearIndicator && (
<components.ClearIndicator {...props}>
<IconClose size='1.25rem' />
</components.ClearIndicator>
)
);
}
export interface SelectMultiProps<Option, Group extends GroupBase<Option> = GroupBase<Option>>
extends Omit<Props<Option, true, Group>, 'theme' | 'menuPortalTarget'> {
noPortal?: boolean;
}
/**
* Displays a multi-select component.
*/
export function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
noPortal,
...restProps
}: SelectMultiProps<Option, Group>) {
const size = useWindowSize();
const adjustedStyles: StylesConfig<Option, true, Group> = {
container: defaultStyles => ({
...defaultStyles,
borderRadius: '0.25rem'
}),
control: (styles, { isDisabled }) => ({
...styles,
borderRadius: '0.25rem',
cursor: isDisabled ? 'not-allowed' : 'pointer',
boxShadow: 'none'
}),
option: (styles, { isSelected }) => ({
...styles,
padding: '0.25rem 0.75rem',
fontSize: '0.875rem',
lineHeight: '1.25rem',
backgroundColor: isSelected ? APP_COLORS.bgSelected : styles.backgroundColor,
color: isSelected ? APP_COLORS.fgSelected : styles.color,
borderWidth: '1px',
borderColor: APP_COLORS.border
}),
menuPortal: styles => ({
...styles,
zIndex: 9999
}),
menuList: styles => ({
...styles,
padding: 0
}),
input: styles => ({ ...styles }),
placeholder: styles => ({ ...styles }),
multiValue: styles => ({
...styles,
borderRadius: '0.5rem',
backgroundColor: APP_COLORS.bgSelected
}),
dropdownIndicator: base => ({
...base,
paddingTop: 0,
paddingBottom: 0
}),
clearIndicator: base => ({
...base,
paddingTop: 0,
paddingBottom: 0
})
};
return (
<Select
isMulti
noOptionsMessage={() => 'Список пуст'}
components={{ DropdownIndicator, ClearIndicator }}
theme={theme => ({
...theme,
borderRadius: 0,
spacing: {
...theme.spacing,
baseUnit: size.isSmall ? 2 : 4,
menuGutter: size.isSmall ? 4 : 8,
controlHeight: size.isSmall ? 28 : 38
},
colors: {
...theme.colors,
...SELECT_THEME
}
})}
menuPortalTarget={!noPortal ? document.body : null}
styles={adjustedStyles}
classNames={{ container: () => 'focus-frame' }}
{...restProps}
/>
);
}

View File

@ -0,0 +1,150 @@
'use client';
import { useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { ChevronDownIcon } from 'lucide-react';
import { IconRemove } from '../icons';
import { type Styling } from '../props';
import { cn } from '../utils';
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command';
import { Popover, PopoverContent, PopoverTrigger } from './popover';
interface ComboMultiProps<Option> extends Styling {
id?: string;
items?: Option[];
value: Option[];
onChange: (newValue: Option[]) => void;
idFunc: (item: Option) => string;
labelValueFunc: (item: Option) => string;
labelOptionFunc: (item: Option) => string;
placeholder?: string;
noSearch?: boolean;
}
/**
* Displays a combo-box component with multiple selection.
*/
export function ComboMulti<Option>({
id,
items,
value,
onChange,
labelValueFunc,
labelOptionFunc,
idFunc,
placeholder,
className,
style,
noSearch
}: ComboMultiProps<Option>) {
const [open, setOpen] = useState(false);
const [popoverWidth, setPopoverWidth] = useState<number | undefined>(undefined);
const triggerRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (triggerRef.current) {
setPopoverWidth(triggerRef.current.offsetWidth);
}
}, [open]);
function handleAddValue(newValue: Option) {
if (value.includes(newValue)) {
handleRemoveValue(newValue);
} else {
onChange([...value, newValue]);
setOpen(false);
}
}
function handleRemoveValue(delValue: Option) {
onChange(value.filter(v => v !== delValue));
setOpen(false);
}
function handleClear(event: React.MouseEvent<SVGElement>) {
event.stopPropagation();
onChange([]);
setOpen(false);
}
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<button
id={id}
ref={triggerRef}
role='combobox'
aria-expanded={open}
className={cn(
'relative h-9',
'flex gap-2 px-3 py-2 items-center justify-between',
'bg-input disabled:opacity-50',
'cursor-pointer disabled:cursor-auto',
'whitespace-nowrap',
'focus-outline border',
"[&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
open && 'cursor-auto',
!value && 'text-muted-foreground',
className
)}
style={style}
>
<div className='flex flex-wrap items-center'>
{value.length === 0 ? <div className='text-muted-foreground'>{placeholder}</div> : null}
{value.map(item => (
<div
key={idFunc(item)}
className={clsx('m-1', 'flex px-1 items-center', 'border rounded-lg', 'bg-accent', 'text-sm')}
>
{labelValueFunc(item)}
<IconRemove
tabIndex={-1}
size='1rem'
className='text-muted-foreground hover:text-destructive'
onClick={event => {
event.stopPropagation();
handleRemoveValue(item);
}}
/>
</div>
))}
</div>
<ChevronDownIcon className={cn('text-muted-foreground', !!value && 'opacity-0')} />
{!!value ? (
<IconRemove
tabIndex={-1}
size='1rem'
className='absolute pointer-events-auto right-3 text-muted-foreground hover:text-destructive'
onClick={handleClear}
/>
) : null}
</button>
</PopoverTrigger>
<PopoverContent sideOffset={-1} className='p-0' style={{ width: popoverWidth }}>
<Command>
{!noSearch ? <CommandInput placeholder='Поиск...' className='h-9' /> : null}
<CommandList>
<CommandEmpty>Список пуст</CommandEmpty>
<CommandGroup>
{items?.map(item => (
<CommandItem
key={idFunc(item)}
value={labelOptionFunc(item)}
onSelect={() => handleAddValue(item)}
className={cn(value === item && 'bg-selected text-selected-foreground')}
>
{labelOptionFunc(item)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

View File

@ -1,27 +1,30 @@
import { SelectMulti, type SelectMultiProps } from '@/components/input';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
import { ComboMulti } from '@/components/ui/combo-multi';
import { Grammeme, type IGrammemeOption } from '../models/language'; import { labelGrammeme } from '../labels';
import { getCompatibleGrams, grammemeCompare, supportedGrammeOptions } from '../models/language-api'; import { type Grammeme, supportedGrammemes } from '../models/language';
import { getCompatibleGrams } from '../models/language-api';
interface SelectMultiGrammemeProps extends Omit<SelectMultiProps<IGrammemeOption>, 'value' | 'onChange'>, Styling { interface SelectMultiGrammemeProps extends Styling {
value: IGrammemeOption[]; id?: string;
onChange: (newValue: IGrammemeOption[]) => void; value: Grammeme[];
onChange: (newValue: Grammeme[]) => void;
placeholder?: string; placeholder?: string;
} }
export function SelectMultiGrammeme({ value, onChange, ...restProps }: SelectMultiGrammemeProps) { export function SelectMultiGrammeme({ value, onChange, ...restProps }: SelectMultiGrammemeProps) {
const compatible = getCompatibleGrams( const compatible = getCompatibleGrams(value);
value.filter(data => Object.values(Grammeme).includes(data.value)).map(data => data.value) const items: Grammeme[] = [...supportedGrammemes.filter(gram => compatible.includes(gram))];
);
const options = supportedGrammeOptions.filter(({ value }) => compatible.includes(value));
return ( return (
<SelectMulti <ComboMulti
options={options} noSearch
items={items}
value={value} value={value}
isSearchable={false} onChange={onChange}
onChange={newValue => onChange([...newValue].sort((left, right) => grammemeCompare(left.value, right.value)))} idFunc={gram => gram}
labelOptionFunc={gram => labelGrammeme(gram)}
labelValueFunc={gram => labelGrammeme(gram)}
{...restProps} {...restProps}
/> />
); );

View File

@ -5,8 +5,7 @@ import clsx from 'clsx';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { Grammeme, type IGrammemeOption } from '../models/language'; import { Grammeme, supportedGrammemes } from '../models/language';
import { supportedGrammeOptions } from '../models/language-api';
import { WordformButton } from './wordform-button'; import { WordformButton } from './wordform-button';
@ -30,13 +29,13 @@ const DefaultWordForms = [
] as const; ] as const;
interface SelectWordFormProps extends Styling { interface SelectWordFormProps extends Styling {
value: IGrammemeOption[]; value: Grammeme[];
onChange: React.Dispatch<React.SetStateAction<IGrammemeOption[]>>; onChange: React.Dispatch<React.SetStateAction<Grammeme[]>>;
} }
export function SelectWordForm({ value, onChange, className, ...restProps }: SelectWordFormProps) { export function SelectWordForm({ value, onChange, className, ...restProps }: SelectWordFormProps) {
function handleSelect(grams: Grammeme[]) { function handleSelect(grams: Grammeme[]) {
onChange(supportedGrammeOptions.filter(({ value }) => grams.includes(value))); onChange(supportedGrammemes.filter(value => grams.includes(value)));
} }
return ( return (
@ -47,7 +46,7 @@ export function SelectWordForm({ value, onChange, className, ...restProps }: Sel
text={data.text} text={data.text}
example={data.example} example={data.example}
grams={data.grams} grams={data.grams}
isSelected={data.grams.every(gram => value.find(item => item.value === gram))} isSelected={data.grams.every(gram => value.find(item => item === gram))}
onSelectGrams={handleSelect} onSelectGrams={handleSelect}
/> />
))} ))}

View File

@ -12,13 +12,14 @@ import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { labelReferenceType } from '../../labels'; import { labelReferenceType } from '../../labels';
import { type IReference, ReferenceType, schemaGrammemeOption, schemaReferenceType } from '../../models/language';
import { import {
parseEntityReference, type IReference,
parseGrammemes, ReferenceType,
parseSyntacticReference, schemaGrammeme,
supportedGrammeOptions schemaReferenceType,
} from '../../models/language-api'; supportedGrammemes
} from '../../models/language';
import { parseEntityReference, parseGrammemes, parseSyntacticReference } from '../../models/language-api';
import { type IRSForm } from '../../models/rsform'; import { type IRSForm } from '../../models/rsform';
import { TabEntityReference } from './tab-entity-reference'; import { TabEntityReference } from './tab-entity-reference';
@ -37,7 +38,7 @@ const schemaEditReferenceState = z
type: schemaReferenceType, type: schemaReferenceType,
entity: z.strictObject({ entity: z.strictObject({
entity: z.string(), entity: z.string(),
grams: z.array(schemaGrammemeOption) grams: z.array(schemaGrammeme)
}), }),
syntactic: z.strictObject({ offset: z.coerce.number(), nominal: z.string() }) syntactic: z.strictObject({ offset: z.coerce.number(), nominal: z.string() })
}) })
@ -82,7 +83,7 @@ export function DlgEditReference() {
type: data.type, type: data.type,
data: { data: {
entity: data.entity.entity, entity: data.entity.entity,
form: data.entity.grams.map(gram => gram.value).join(',') form: data.entity.grams.join(',')
} }
}); });
} else { } else {
@ -138,7 +139,7 @@ function initEntityReference(initial: IReferenceInputState) {
} else { } else {
const ref = parseEntityReference(initial.refRaw); const ref = parseEntityReference(initial.refRaw);
const grams = parseGrammemes(ref.form); const grams = parseGrammemes(ref.form);
const supported = supportedGrammeOptions.filter(data => grams.includes(data.value)); const supported = supportedGrammemes.filter(data => grams.includes(data));
return { return {
entity: ref.entity, entity: ref.entity,
grams: supported grams: supported

View File

@ -77,7 +77,6 @@ export function TabEntityReference() {
id='dlg_reference_grammemes' id='dlg_reference_grammemes'
placeholder='Выберите граммемы' placeholder='Выберите граммемы'
className='grow' className='grow'
menuPlacement='top'
value={field.value} value={field.value}
onChange={field.onChange} onChange={field.onChange}
/> />

View File

@ -17,8 +17,8 @@ import { useIsProcessingCctext } from '../../backend/cctext/use-is-processing-cc
import { useParseText } from '../../backend/cctext/use-parse-text'; import { useParseText } from '../../backend/cctext/use-parse-text';
import { useCstUpdate } from '../../backend/use-cst-update'; import { useCstUpdate } from '../../backend/use-cst-update';
import { SelectMultiGrammeme } from '../../components/select-multi-grammeme'; import { SelectMultiGrammeme } from '../../components/select-multi-grammeme';
import { type IGrammemeOption, type IWordForm, supportedGrammemes } from '../../models/language'; import { type Grammeme, type IWordForm, supportedGrammemes } from '../../models/language';
import { parseGrammemes, supportedGrammeOptions, wordFormEquals } from '../../models/language-api'; import { parseGrammemes, wordFormEquals } from '../../models/language-api';
import { type IConstituenta } from '../../models/rsform'; import { type IConstituenta } from '../../models/rsform';
import { TableWordForms } from './table-word-forms'; import { TableWordForms } from './table-word-forms';
@ -38,7 +38,7 @@ export function DlgEditWordForms() {
const { generateLexeme } = useGenerateLexeme(); const { generateLexeme } = useGenerateLexeme();
const [inputText, setInputText] = useState(target.term_resolved); const [inputText, setInputText] = useState(target.term_resolved);
const [inputGrams, setInputGrams] = useState<IGrammemeOption[]>([]); const [inputGrams, setInputGrams] = useState<Grammeme[]>([]);
const [forms, setForms] = useState<IWordForm[]>( const [forms, setForms] = useState<IWordForm[]>(
target.term_forms.map(term => ({ target.term_forms.map(term => ({
@ -65,27 +65,27 @@ export function DlgEditWordForms() {
function handleAddForm() { function handleAddForm() {
const newForm: IWordForm = { const newForm: IWordForm = {
text: inputText, text: inputText,
grams: inputGrams.map(item => item.value) grams: inputGrams
}; };
setForms(forms => [newForm, ...forms.filter(value => !wordFormEquals(value, newForm))]); setForms(forms => [newForm, ...forms.filter(value => !wordFormEquals(value, newForm))]);
} }
function handleSelectForm(form: IWordForm) { function handleSelectForm(form: IWordForm) {
setInputText(form.text); setInputText(form.text);
setInputGrams(supportedGrammeOptions.filter(gram => form.grams.find(test => test === gram.value))); setInputGrams(supportedGrammemes.filter(gram => form.grams.find(test => test === gram)));
} }
function handleInflect() { function handleInflect() {
void inflectText({ void inflectText({
text: target.term_resolved, text: target.term_resolved,
grams: inputGrams.map(gram => gram.value).join(',') grams: inputGrams.join(',')
}).then(response => setInputText(response.result)); }).then(response => setInputText(response.result));
} }
function handleParse() { function handleParse() {
void parseText({ text: inputText }).then(response => { void parseText({ text: inputText }).then(response => {
const grams = parseGrammemes(response.result); const grams = parseGrammemes(response.result);
setInputGrams(supportedGrammeOptions.filter(gram => grams.find(test => test === gram.value))); setInputGrams(supportedGrammemes.filter(gram => grams.find(test => test === gram)));
}); });
} }
@ -159,7 +159,7 @@ export function DlgEditWordForms() {
</div> </div>
<SelectMultiGrammeme <SelectMultiGrammeme
placeholder='Выберите граммемы' placeholder='Выберите граммемы'
className='min-w-60 h-fit' className='w-60 h-fit'
value={inputGrams} value={inputGrams}
onChange={setInputGrams} onChange={setInputGrams}
/> />

View File

@ -2,19 +2,15 @@
* Module: Natural language model API. * Module: Natural language model API.
*/ */
import { labelGrammeme } from '../labels';
import { import {
Grammeme, Grammeme,
GrammemeGroups, GrammemeGroups,
type IEntityReference, type IEntityReference,
type IGrammemeOption,
type IReference, type IReference,
type ISyntacticReference, type ISyntacticReference,
type IWordForm, type IWordForm,
NounGrams, NounGrams,
ReferenceType, ReferenceType,
supportedGrammemes,
VerbGrams VerbGrams
} from './language'; } from './language';
@ -122,14 +118,6 @@ export function parseSyntacticReference(text: string): ISyntacticReference {
}; };
} }
/**
* Represents options for {@link Grammeme} selector.
*/
export const supportedGrammeOptions: IGrammemeOption[] = supportedGrammemes.map(gram => ({
value: gram,
label: labelGrammeme(gram)
}));
/** /**
* Transforms {@link IReference} to string representation. * Transforms {@link IReference} to string representation.
*/ */

View File

@ -230,13 +230,6 @@ export const supportedGrammemes = [
Grammeme.accs, Grammeme.ablt, Grammeme.loct, Grammeme.accs, Grammeme.ablt, Grammeme.loct,
] as const; ] as const;
export const schemaGrammemeOption = z.strictObject({
value: schemaGrammeme,
label: z.string()
});
export type IGrammemeOption = z.infer<typeof schemaGrammemeOption>;
// ====== Reference resolution ===== // ====== Reference resolution =====
/** Represents text reference type. */ /** Represents text reference type. */

View File

@ -19,7 +19,7 @@ export const APP_COLORS = {
fgDefault: 'var(--clr-prim-999)', fgDefault: 'var(--clr-prim-999)',
fgSelected: 'var(--clr-prim-999)', fgSelected: 'var(--clr-prim-999)',
fgDisabled: 'var(--clr-prim-800)', fgMuted: 'var(--clr-prim-600)',
fgWarning: 'var(--clr-warn-600)', fgWarning: 'var(--clr-warn-600)',
bgRed: 'var(--acc-bg-red)', bgRed: 'var(--acc-bg-red)',
@ -40,26 +40,3 @@ export const APP_COLORS = {
fgTeal: 'var(--acc-fg-teal)', fgTeal: 'var(--acc-fg-teal)',
fgOrange: 'var(--acc-fg-orange)' fgOrange: 'var(--acc-fg-orange)'
} }
/** Represents Select component theme. */
export const SELECT_THEME = {
primary: APP_COLORS.bgPrimary,
primary75: APP_COLORS.bgSelected,
primary50: APP_COLORS.bgHover,
primary25: APP_COLORS.bgHover,
danger: APP_COLORS.fgWarning,
dangerLight: APP_COLORS.bgWarning,
neutral0: APP_COLORS.bgInput,
neutral5: APP_COLORS.bgDefault,
neutral10: APP_COLORS.border,
neutral20: APP_COLORS.border,
neutral30: APP_COLORS.border,
neutral40: APP_COLORS.fgDisabled,
neutral50: APP_COLORS.fgDisabled, // placeholder
neutral60: APP_COLORS.fgDefault,
neutral70: APP_COLORS.fgWarning,
neutral80: APP_COLORS.fgDefault,
neutral90: APP_COLORS.fgWarning
};