Compare commits

...
Author SHA1 Message Date
Ruslan 90ae597a66 dbeaver/pro#5630 fix images 2025-07-29 16:33:18 +02:00
Evgenia 885e2c16fe Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-29 15:16:42 +02:00
Wroud 6156675fb9 fix: do not use cache if result dataFormat changed 2025-07-29 20:06:59 +08:00
Alexey PotsetsuevandEvgenia ad6973d069 dbeaver/pro#6337 fix: sql editor dnd insertion (#3620)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-29 19:53:03 +08:00
sergeyteleshevandmr-anton-t 231da5b0b8 6056-cb-impelement-ui-kit-select-in-combobox (#3557)
* dbeaver/pro#6056 adds boilerplate for new combobox ui kit

* removes unused code

* refactors layout

* fixes theme styles

* fixes styles

* fixes search value

* implements ui kit store instead of menu

* reverts search value changes

* fixes search

* cleanup

* adds ellipsis on select items

* selectField supports required for form validations

* adds types for functions

* adds disabled styles

* removes hover border-color for disabled select

* removes popoverProps

* moves some styles from kit select to combobox + fixes some styles

* fixes for QA

* adds custom paddings as it was before refactoring

* fixes item styles, placeholder, title errors

* fixes focus styles for input

* fixes expanded state focus

* splits to Select and Combobox

* removes unused code for select

* pr fixes

* replaces arrow icon + opens select on label click

* fixes click on label

* Revert "fixes click on label"

This reverts commit 772c988b28.

* reverts select label

* removes 1/3 width for preferences

* removes border radius from top of the navigation tab

* fixes selection element

* removes double select border

* qa fixes

* fixes border-radius and outline-offset for select

* fixes outline

* fixes colors

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-07-29 19:52:34 +08:00
Evgenia 945802cb23 Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-29 13:20:53 +02:00
Alexander Skoblikovandkseniaguzeeva 57e77b7cd1 dbeaver/pro#6303 do not remove default user team (#3609)
* dbeaver/pro#6303 do not remove default user team

* dbeaver/pro#6303 throw error

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-07-29 13:17:09 +02:00
Wroud 74bea16b2f Merge branch 'dbeaver/pro#6401/fix/async-task-update-after-finish' into dbeaver/pro#5630-add-cache-for-queries 2025-07-29 19:16:38 +08:00
Evgenia 9a9445ca01 Merge branch 'devel' into dbeaver/pro#6401/fix/async-task-update-after-finish 2025-07-29 10:54:35 +02:00
mr-anton-t c7b2980a30 Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-28 17:54:07 +02:00
Ruslan 08f4e469e3 dbeaver/pro#5630 fix npe 2025-07-28 17:39:47 +02:00
Alexey Potsetsuev 58c4744aa7 dbeaver/pro#6417 chore: update deps (#3616) 2025-07-28 22:49:30 +08:00
Sychev AndreyandEvgenia 39c7346e0a dbeaver/pro#5720 feat: add Script button for tables w/o identifier (#3608)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-28 22:46:51 +08:00
Ruslan 97cee0127d dbeaver/pro#5630 fix npe 2025-07-28 15:31:58 +02:00
Wroud d03b00e30a dbeaver/pro#6401 fix: async task update after finish 2025-07-28 19:56:06 +08:00
mr-anton-t c200d5743a Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-28 10:53:38 +02:00
131b1e13f4 dbeaver/pro#6109 add void type (#3603)
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-27 15:17:41 +02:00
Daria Marutkina a1d3edcb82 Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-25 16:12:45 +02:00
Sychev AndreyandDaria Marutkina 3914461f55 dbeaver/pro#5161 fix: show confirmation message if there is unsaved changes in teams form (#3605)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-25 15:30:37 +02:00
Sychev Andrey 5dc6e5ca38 dbeaver/cloudbeaver#3569 fix: don't show new connection button (#3604) 2025-07-25 15:27:52 +02:00
Daria Marutkina f0004d112b Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-25 15:24:49 +02:00
alex c747c30063 dbeaver/pro#6399 do not check executable feature (#3610) 2025-07-25 14:54:31 +02:00
ad225404f4 dbeaver/pro#6124 Add audit log cleanup job (#3591)
* dbeaver/pro#6124 Add audit log cleanup job

* dbeaver/pro#6124 fixes

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2025-07-24 17:47:12 +02:00
sergeyteleshev d9fe873bb5 dbeaver/pro#6383 reverts stylus stub (#3606) 2025-07-24 12:08:09 +02:00
sergeyteleshev 0193e67f72 dbeaver/pro#6372 adds stub for stylus lib (#3601) 2025-07-23 15:44:17 +02:00
Daria Marutkina 3c34ce5f71 Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-23 09:22:51 +02:00
8ebf7eba9c dbeaver/pro#5886 core api for permission management (#3519)
* dbeaver/pro#5886 new permissions api

* dbeaver/pro#5886 new permissions api

* dbeaver/pro#5886 test + forgotten commit

* dbeaver/pro#5886 test + forgotten commit, review fixes

* dbeaver/#5886 test + forgotten commits

* dbeaver/pro#5886 clean up CE repos

* dbeaver/pro#5886 gql api for global perms

* dbeaver/pro#5886 new perms validation

* dbeaver/pro#5886 remove unused class

* dbeaver/pro#5886 new api

* chore: update permission key

* dbeaver/pro#5087 feat: permissions management

* feat: check permission for query execution

* fix: override only restrictive permissions

* fix: permissions layer

* fix: status gutter duplication

* fix: script execution error message display

* fix: hide not available script execution actions

* dbeaver/pro#5886 anon perms fix, default value for global perms

* fix: hide settings groups only for specific settings

* feat: restore permissions

* refactor: after review

* fix: merge conflicts

* fix: type import

* fix: merge conflicts

* fix: linting

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
2025-07-23 03:56:43 +02:00
AnastasiyaandDaria Marutkina 848b95113a dbeaver/cloudbeaver#3590 update DuckDB driver till version 1.3.2 (#3592)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-22 11:32:41 +02:00
sergeyteleshevandmr-anton-t d4c304f725 [CB] write unit tests (#3593)
* dbeaver/pro#6312 adds unit tests for helpers

* updates yarn locks

* lint fix

* restores mock

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-07-22 09:41:08 +02:00
sergeyteleshev 444ff0d672 [CB] fix unit tests issue with console mocking (#3589)
* dbeaver/pro#6288 adds init for console mocks

* test fix 2

* test fix 3

* test fix 4

* resetets deprecated settings
2025-07-22 09:33:33 +02:00
Ruslan 52e2ee4a70 dbeaver/pro#5630 add soft reference 2025-07-21 13:33:31 +02:00
Daria Marutkina bf49a94642 dbeaver/pro#6275 Update README file (#3596) 2025-07-21 11:11:39 +02:00
JeremyandEvgenia 3a2e41fa69 feat: upgrade databend-jdbc to v0.3.9 (#3540)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-21 08:59:53 +02:00
Alexey PotsetsuevandEvgenia 36e8d1fac9 dbeaver/pro#6201 feat: ai chat query insertion (#3578)
* dbeaver/pro#6201 feat: ai chat query insertion

* chore: remove confusing comment

* chore: query execution and replacement

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-18 23:44:17 +08:00
sergeyteleshev dcc13811e8 [CB] fix frontend linter to pass the github action (#3588)
* dbeaver/pro#6272 initial commit to see errors

* removes func-call-spacing from rules

* removes func-call-spacing from rules 2

* fixes flat file for stylistic

* try to update stylistic

* Revert "try to update stylistic"

This reverts commit 459bf77714.

* reverts rule

* tries function-call-spacing

* test linter rule

* Revert "test linter rule"

This reverts commit 0b0fb66b69.
2025-07-18 19:51:16 +08:00
Ruslan 93972f8af8 dbeaver/pro#5630 cache sql queries 2025-07-16 19:22:20 +02:00
Ruslan 65a99475e8 dbeaver/pro#5630 cache sql queries 2025-07-16 19:10:18 +02:00
Ruslan aa489ccd31 Merge remote-tracking branch 'origin/dbeaver/pro#5630-add-cache-for-queries' into dbeaver/pro#5630-add-cache-for-queries 2025-07-16 15:06:02 +02:00
Ruslan d90a765cc7 dbeaver/pro#5630 cache sql queries 2025-07-16 15:05:25 +02:00
Wroud 550373f48e fix: check added constraints 2025-07-16 20:56:33 +08:00
Ruslan 636725681a Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-16 13:52:36 +02:00
Ruslan 14de42933e dbeaver/pro#5630 cache sql queries 2025-07-15 19:34:27 +02:00
Serge Rider 2ba910386f dbeaver/pro#6275 25.1.4 version bump 2025-07-15 20:21:32 +03:00
Serge Rider a7c5d53f0a dbeaver/pro#6275 25.1.4 version bump 2025-07-15 20:20:39 +03:00
Ainur 59f0da9caa dbeaver/pro#5399 fix merge conflict (#3587) 2025-07-15 19:08:33 +02:00
4d5c58316c dbeaver/pro#5399 Add new completion engine to cloudbeaver (#3535)
* dbeaver/pro#5399 Add new completion engine to cloudbeaver

* dbeaver/pro#5399 Fixes and update icon references

* dbeaver/pro#5399 Add new completion engine to cloudbeaver

* dbeaver/pro#5399 add sync config with desktop

* dbeaver/pro#5399 fix fallback to default engine

* dbeaver/pro#5399 feat: add labels for content assistant setting

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Sychev Andrey <nukemoore@gmail.com>
2025-07-15 18:43:43 +02:00
bae21e5b2e Dbeaver/pro#5864 add audit logging (#3556)
* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 Add audit logging

* dbeaver/pro#5864 fix review

* dbeaver/pro#5864 fix review

* dbeaver/pro#5864 fixes

* dbeaver/pro#5864 add file name upload logging

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2025-07-15 16:11:37 +02:00
Ruslan 18bc462ad0 Merge remote-tracking branch 'origin/dbeaver/pro#5630-add-cache-for-queries' into dbeaver/pro#5630-add-cache-for-queries 2025-07-15 14:09:56 +02:00
Alexey Potsetsuev 964cd76178 Merge branch 'devel' into dbeaver/pro#5630-add-cache-for-queries 2025-07-15 20:06:06 +08:00
Ruslan 9ba77d490a dbeaver/pro#5630 cache sql queries 2025-07-15 14:06:03 +02:00
Wroud 3dddd20dcb fix: grouping 2025-07-15 20:03:50 +08:00
Wroud 8c7c3a545d fix: don't cache refresh requests 2025-07-15 20:03:03 +08:00
Wroud 4068c556df feat: use cache for data queries 2025-07-15 19:30:34 +08:00
Ruslan 2e273e0d6c dbeaver/pro#5630 cache sql queries 2025-07-15 13:03:10 +02:00
Ruslan 6dee34b1a7 dbeaver/pro#5630 cache sql queries 2025-07-15 12:57:40 +02:00
5ce5f6e10d dbeaver/pro#6042 get node features from feature provider (#3581)
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2025-07-15 12:27:42 +02:00
Ruslan 298a4e3310 dbeaver/pro#5630 cache sql queries 2025-07-15 12:20:54 +02:00
sergeyteleshevandEvgenia db28b2ad2c dbeaver/pro#6251 moves settings to interface + fixes border-size for selected tab (#3584)
* dbeaver/pro#6251 moves settings to interface + fixes border-size for selected tab

* applies borders only for navigation tabs

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-15 17:48:12 +08:00
Sychev AndreyandDaria Marutkina d58b3e14a2 dbeaver/pro#6105 fix: form validation fails on test in GCP (#3583)
Removed active state from Options component resources because it unload resources when we switch to other tabs which leads to broken connection form state and entails data inconsistency.

For example, the check driver?.useCustomPage fails because driver resource has been unloaded and the component renders standard Parameters from instead of custom taking state from the wrong destination.

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-15 17:47:34 +08:00
Alexander Skoblikovandkseniaguzeeva c476a56661 dbeaver/pro#5816 link websession with address (#3564)
* dbeaver/pro#5816 link websession with address

* dbeaver/pro#5816 flag to disable ip binging

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-07-14 19:06:52 +02:00
Ruslan db210317a3 dbeaver/pro#5830 cache 2025-07-14 17:10:56 +02:00
79804619d3 dbeaver/pro#4863 Add column description to data editor (#3573)
* dbeaver/pro#4863 Add column description to data editor

* adds description for columns + settings

* alignes description with column name

* pr fixes

* adds skip to the settings test

* makes header more compact

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-14 21:25:58 +08:00
Ruslan 76f7e8b9d7 dbeaver/pro#5630 Add cache for queries 2025-07-14 12:52:02 +02:00
Sychev AndreyandDaria Marutkina 1c7300cdf1 dbeaver/pro#5455 Feat: add repeat password field in easyconfig (#3570)
* dbeaver/pro#5455 feat: add repeat password field in configuration wizard

* dbeaver/pro#5455 refactor: connect repeat password field with form validation via state

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-14 17:26:24 +08:00
9b2cb7cc92 [CB] Multiple tabs row support (#3563)
* dbeaver/pro#5904 adds navigation multiple tabs support

* adds tabs box container

* fixes bug with invisible object viewer tabs

* cleanup

* Revert "cleanup"

This reverts commit a519421bb0.

* Revert "fixes bug with invisible object viewer tabs"

This reverts commit 03b8e7b1cc.

* Revert "adds tabs box container"

This reverts commit c6f247ed64.

* removes extra pixels for border

* adds more proper setting description

* removes extra dots

* skips tests

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Alexey Potsetsuev <wrouds@gmail.com>
2025-07-11 20:51:05 +08:00
Ruslan MusaevandDaria Marutkina 5022c01468 dbeaver/pro#4739 Fix losing context execution after node refreshing (#3572)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-10 16:44:50 +02:00
Sychev AndreyandAlexey Potsetsuev 60fb6c5a3b dbeaver/pro#4990 feat: add SSL configuration documentation (#3575)
* dbeaver/pro#4990 feat: add SSL configuration documentation

* dbeaver/pro#4990 refactor: use proper product name

* dbeaver/pro#4990 fix: use sm icon for SSL docs link

* dbeaver/pro#4990 fix: extra space in l10n string

---------

Co-authored-by: Alexey Potsetsuev <wrouds@gmail.com>
2025-07-10 17:54:17 +08:00
sergeyteleshev 6889b51ab6 dbeaver/pro#6221 skips settings test (#3580)
* dbeaver/pro#6221 skips settings test

* lint fix

* lint fix 2

* lint fix 3

* lint fix 4

* reverts all lint fixes
2025-07-10 17:52:05 +08:00
a7e09b5e16 dbeaver/pro#5558 license user management from app (#3504)
* dbeaver/pro#5558 license user management from app

* dbeaver/pro#5558 fixes after test

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-07-10 04:11:22 +02:00
Dmitrii BarnukovandMatvey16 0746a7a2c4 dbeaver/pro#4025 Downgrade db2 default driver version to 11.5.9 (#3574)
Co-authored-by: Matvey16 <82543000+Matvey16@users.noreply.github.com>
2025-07-10 04:01:26 +02:00
Alexey Potsetsuevandmr-anton-t f5380093ca dbeaver/pro#5763 chore: update deps (#3571)
* dbeaver/pro#5763 chore: update deps

* fix: linting

* chore: fix gql client

* chore: force version upgrade

* fix: gql error catching

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-07-10 03:09:19 +08:00
alexandDaria Marutkina dd4691c650 dbeaver/pro#6150 sync options part (#3577)
* dbeaver/pro#6150 sync options part

* dbeaver/pro#6150 reset unsaved properties properly

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-10 03:08:46 +08:00
55db159560 dbeaver/pro#6075 remove commit hooks (#3548)
* dbeaver/pro#6075 remove commit hooks

* dbeaver/pro#6075 do not run pre-commit hooks on merge and rebase

* dbeaver/pro#6075 reuse logic

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-07-09 02:12:20 +08:00
Alexander Skoblikov dcdea93687 dbeaver/pro#6148 add x-origin header support (#3565) 2025-07-08 11:40:27 +00:00
sergeyteleshevandEvgenia 54b5db9480 [CB] SQL Editor - container blinks when changing scheme (#3562)
* dbeaver/pro#6008 fixes blink on schema change

* fixes update for execution context so mobx catch it right

* Revert "dbeaver/pro#6008 fixes blink on schema change"

This reverts commit be1e828511.

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-07 20:32:46 +08:00
Daria Marutkina aa84d79e93 dbeaver/pro#6147 Update README file (#3567) 2025-07-07 11:23:32 +02:00
sergeyteleshev 9bc28083fd dbeaver/pro#3558 removes unused code (#3561) 2025-07-03 23:08:19 +08:00
Serge Rider cb03b507b3 dbeaver/pro#6147 25.1.3 version bump 2025-07-01 21:20:43 +03:00
Ruslan MusaevandAinur 9ffa5088db dbeaver/pro#6137 Fix png cache images (#3560)
* dbeaver/pro#6137 Fix png cache images

* dbeaver/pro#6137 Fix png cache images

---------

Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2025-07-01 18:02:19 +02:00
Ruslan MusaevandEvgenia e7dcc93706 Dbeaver/pro#5266 extract data export file limit parametr to preference (#3529)
* dbeaver/pro#5266 Extract dataExportFileLimit parameter to preference

* Revert "dbeaver/pro#5266 Extract dataExportFileLimit parameter to preference"

This reverts commit 7f1c5920dc.

* dbeaver/pro#5266 Remove dataExportFileLimit parameter

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-07-01 18:02:06 +02:00
alexandDaria Marutkina ad3ae4547c dbeaver/pro#5486 use new pointer events instead of mouse (#3549)
* dbeaver/pro#5486 use new pointer events instead of mouse

* dbeaver/pro#5486 reset hover on menu close

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-01 21:36:59 +08:00
dce7797bba [CB] move radio button to ui-kit #6031 (#3533)
* dbeaver/pro#6031 replaces old radio button with ui-kit one

* lint fix

* Update webapp/packages/core-blocks/src/FormControls/RadioGroup.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* pr fixes

* adds labelledby for options configType

* adds gap:0 for vertical radio group

* pr fixes

* cleanup

* radio button fixes for dark theme

* nowrap for radio button words

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-07-01 21:36:37 +08:00
AlexeyandDaria Marutkina 7c0d666b0a dbeaver/pro#5122 fix: settings alias resolving (#3544)
* dbeaver/pro#5122 fix: settings alias resolving

* chore: skip failing tests

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-07-01 19:57:28 +08:00
Tsimafei LabanovichandMatvey16 c5a2bcdcbf dbeaver/pro#4800 Update db2 driver version (#3460)
Co-authored-by: Matvey16 <82543000+Matvey16@users.noreply.github.com>
2025-07-01 13:17:40 +02:00
sergeyteleshev 85a242bf34 dbeaver/pro#6113 fixes clientActivity wrong spying on SetTimeout (#3559) 2025-06-30 18:10:54 +08:00
2117840e40 [CB] 'Same as device' theme setting #5445 (#3555)
* dbeaver/pro#5445 adds system theme

* cleanup

* adds queries to consts

* fix: review

* fixes bugs with subscriptions + translations + cleans up

* adds settings keys type

---------

Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-30 16:39:16 +08:00
ShadelessFoxandmr-anton-t 9fec1ce5a5 dbeaver/pro#6039 Migrate to SVG icons (#3542)
* dbeaver/pro#6039 Migrate to SVG icons

* dbeaver/pro#6039 SVG content type fix

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-30 08:31:38 +02:00
Ainurandmr-anton-t 88ef237566 dbeaver/pro#5813 add description for graphql queries (#3496)
* dbeaver/pro#5813 add description for graphql queries

* dbeaver/pro#5813 do not use deprecated word in the description

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-27 15:39:16 +02:00
Sychev AndreyandDaria Marutkina cb84409701 dbeaver/pro#5998 Fix: can't copy the whole table selected with the corner cell (#3550)
* dbeaver/pro#5998 fix: selectAll index header cell

* dbeaver/pro#5998 fix: removed OrderButton from tabbing order, add sorting on space/enter when header column cell is in focus

* dbeaver/pro#5998 feat: add onHeaderKeyDown handler to DataGrid and HeaderCellContentRenderer

we lost ability to copy data grid cells' data when one of the header cells is focused, because the header cell renderer was not handling keydown events. This commit utilizing gridSelectedCellCopy.onKeydownHandler inside HeaderCellContentRenderer keydown event handler

* dbeaver/pro#5998 style: change onKeyDown to a named function

* dbeaver/pro#5998 refactor: simplify OrderButton and update sorting logic in HeaderCellContentRenderer

* dbeaver/pro#5998 refactor: rename container class to clickAreaOverlay in TableIndexColumnHeader, remove z-index

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-27 18:23:37 +08:00
Sychev AndreyandDaria Marutkina 69330aa0fe dbeaver/pro#6038 fix: can't click on checkbox in OutputLogMenu (#3539)
* dbeaver/pro#6038 fix: can't click on checkbox in OutputLogMenu

* dbeaver/pro#6038 refactor: update menu item and tree node styles

replace theme-ripple classname with in-place styles  for hover and active states

* dbeaver/pro#6038 refactor: move pointer events none in MenuItemIcon class

* Revert "dbeaver/pro#6038 refactor: update menu item and tree node styles"

This reverts commit 2c2fdc2e8d.

* dbeaver/pro#6038 revert changes made in this branch and #5997, #5989

previous manipulations with theme-ripple class has broken our UI in several places. this PR returns to the state before #5989 when only CloudExplorerTree was broken

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-27 18:23:20 +08:00
Sychev AndreyandEvgenia 76fab9d179 dbeaver/pro#5242 Fix: make the expand tree button focusable from keyboard in the admin part (#3551)
* dbeaver/pro#5242 refactor: update TableItemExpand component

replace a div with IconButton and clean up CSS

* dbeaver/pro#5242 refactor: adjust outline offset for icon button

Usually icon buttons are used inside other components or in small places, so they tend to overflow over their container with a standard button outline offset. I believe that offset 0 is the better default for the IconButton.

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-26 23:57:00 +08:00
Sychev AndreyandDaria Marutkina feed398b6d dbeaver/pro#5820 fix: value panel truncate text (#3554)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-26 23:31:05 +08:00
8422e695ea dbeaver/pro#5538 AI chat (#3520)
* dbeaver/pro#5538 add ai message chunk event

* dbeaver/pro#5538 add events to schema

* dbeaver/pro#5538 add general delete message

* dbeaver/pro#5538 add date time for conversation and fix api

* dbeaver/pro#5538 add change connection executor

* dbeaver/pro#5538 add error event model and rename type

* dbeaver/pro#5538 save metadata param in user preferences

* dbeaver/pro#5538 revert connection change executor

* dbeaver/pro#5538 add className to alert comp

* dbeaver/pro#5538 add connect listener

* dbeaver/pro#5538 add executeEditorQuery method to navigator service

* dbeaver/pro#5538 merge fixes

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-26 16:26:49 +02:00
7fd2548c9c [CB] implement ui-kit spinner #6017 (#3532)
* dbeaver/pro#6017 adds new ui spinner to loader

* removes unused code

* pr fixes

* changes loader animation

* dbeaver/pro#6017 fix: remove class names that don't exist

* dbeaver/pro#6017 fix: remove cloudbeaver spinner animation adjustments

* dbeaver/pro#6017 feat: introduce animation delay variable for spinner

Make the initial appearance of the spinner better by starting from semi-filled circle, not the tine dot which is crucial on fast loads.

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Sychev Andrey <nukemoore@gmail.com>
2025-06-26 22:26:36 +08:00
Sychev AndreyandEvgenia dc8407ad35 dbeaver/pro#4745 Use new tree for cloud explorer (#3523)
* dbeaver/pro#4745 fix: useTreeFilter UX bug

When a user searched for a term (e.g., 're') and found a matching node in the middle of the tree, the user expected to expand that node and see all its children.
But the filter was also being applied to the children, hiding non-matching children. This created a confusing experience where expanding a found node might show empty or partially empty results

In new implementation Tree shows ALL children without filtering if parent node matches filter.

* dbeaver/pro#4745 refactor: update children prop type and usage in AuthenticationProvider

* dbeaver/pro#4745 refactor: replace Loader with Spinner in TreeNodeExpand

* dbeaver/pro#4745 refactor: update typography styles with global typography styles

* dbeaver/pro#4745 feat: add naive tree selection functionality with useTreeSelection hook

* dbeaver/pro#4745 feat: enhance tree selection with loading state management

* dbeaver/pro#4745 feat: add indeterminate selection state management in tree component

* dbeaver/pro#4745 feat: add multiple selection prop in tree component

* dbeaver/pro#4745 refactor: improve indeterminate state management in tree selection

* dbeaver/pro#4745 feat: add expandOnSelect prop to tree and selection hooks

* dbeaver/pro#4745 refactor: adjust padding in CommonDialogHeader styles and fix formatting

* dbeaver/pro#4745 refactor: implement tree selection context for improved node selection management

* dbeaver/pro#4745 style: update padding-left to use CSS variable for treeNodeNested

* dbeaver/pro#4745 refactor: remove redundant state update for empty child nodes in expandNode

It make no sense to close just expanded node if there is no children. User will lost the information about that and could try to open it again later. It's better to keep expanded state to show that this node is empty.

* dbeaver/pro#4745 style: fix lint

* dbeaver/pro#4545 fix: remove useLayoutEffect with focus in TreeNodeControl

This auto focus behavior entailed several bugs like stealing focus from filter input or breaking custom node elements like menu on hover. Decided to remove.

* dbeaver/pro#4745 refactor: make useTreeSelection hook public

* dbeaver/pro#4745 refactor: update tree selection logic and remove unused properties

* dbeaver/pro#4745 refactor: remove async

* dbeaver/pro#4745 refactor: remove duplicated typography styles

* dbeaver/pro#4745 refactor: update selection

* dbeaver/pro#4745 refactor: simplify selection state management in useTreeSelection

* dbeaver/pro#4745 refactor: optimize selection  logic in useTreeSelection

* dbeaver/pro#4745 fix: revert children type

* dbeaver/pro#4745 style: lint

* dbeaver/pro#4745 refactor: expose process action from tree node context

* dbeaver/pro#4745 refactor: remove optional showInFilter property from INodeState interface

* dbeaver/pro#4745 refactor: simplify indeterminate state updates and optimize child selection handling

* dbeaver/pro#4745 fix: bug with bad selection state when select with filters

* dbeaver/pro#4745 refactor: update selection context and method names in tree selection

* dbeaver/pro#4745 feat: add disabled prop to Node component

* dbeaver/pro#4745 refactor: remove disabled prop from Node interface

clean unused TreeNodeSelect code

* dbeaver/pro#4745 add action.bound for processAction

* dbeaver/pro#4745 fix: close/deselect node if loading failed

* dbeaver/pro#4745 feat: enhance tree filter functionality with expanded state management

parent nodes are expanded if node matches with filters. When filters are cleared, the tree restores it's unfiltered expand state

* dbeaver/pro#4545 feat: integrate notification service to show errors on load

* dbeaver/pro#4745 fix: don't  select empty folders

* Revert "dbeaver/pro#4545 feat: integrate notification service to show errors on load"

This reverts commit c1fd855a94.

* dbeaver/pro#4745 feat: add state transformer to tree filter for expanded state management

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-26 21:30:41 +08:00
Mikhailov Grigorii 4379ba8ce7 dbeaver/pro#6036 Added apt-get dist-upgrade to upgrade current packages in ubuntu and fix CVEs (#3553) 2025-06-26 14:51:54 +02:00
sergeyteleshevandEvgenia eaeb493d6b [CB-6221] Add a Clear button to the Output log #4410 (#3547)
* dbeaver/pro#4410 adds clear button for output logs

* pr fixes

* pr fixes

* lint fix

* removes logs only for specific context

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-26 19:05:29 +08:00
mayer 9de5f9508f dbeaver/dbeaver-devops#1924 use stable java base image instead of latest (#3546) 2025-06-25 12:12:27 +02:00
Alexander Skoblikov 93cbaa673f dbeaver/pro#6076 remove debug logs (#3543) 2025-06-25 08:32:01 +00:00
Sychev AndreyandEvgenia 646ec5c901 dbeaver/pro#6018 fix: context menu disappears on cells with an intera… (#3538)
* dbeaver/pro#6018 fix: context menu disappears on cells with an interactive formatter

add menu visibility handling to cell formatters

* dbeaver/pro#6018 refactor: rename handleStateSwitch to handleCellMenuStateSwitch for clarity

* dbeaver/pro#6018 refactor: rename menu visibility properties for clarity

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-24 17:57:35 +08:00
sergeyteleshevandEvgenia beecc84d14 [CB] SQL editor - ctrl+z during autosave scrolls the script to the top #5645 (#3470)
* dbeaver/pro#5645 removes scroll to top for sql editor

* removes floating second scroll bar on ctrl+z

* removes cursor jumping + removes scrolling to top

* reverts layout scroll behavior

* reverts layout scroll behavior 2

* removes unneeded cursorOffset

* removes offset and unused code

* reverts has insert property behavior

* remembers previous cursor position from history

* adds mobx action

* reverts insert property logic

* fixes cursor position during ctrl+z

* Revert "fixes cursor position during ctrl+z"

This reverts commit d1aac8e750.

* dbeaver/pro#5645 sets cursor in sync with code mirror onChange event

* eslint fix

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-23 19:44:18 +08:00
Evgenia ab0df706bb Update README.md - 25.1.1 RN (#3541) 2025-06-23 13:16:12 +02:00
Tiandong Qiu 5edd0142af #38420 P2 repo link fix (#3537) 2025-06-23 12:04:35 +02:00
serge-rider 3c49650bc3 Type check fix 2025-06-20 10:59:02 +02:00
serge-rider f286ab4b3c Overflow fix 2025-06-20 10:22:12 +02:00
serge-rider 7dc9a9daa7 dbeaver/pro#6010 25.1.2 version bump 2025-06-17 20:13:59 +02:00
7f353e9169 dbeaver/pro#5127 Send event if driver config was updated (#3516)
* dbeaver/pro#5127 Send event if driver config was updated

* dbeaver/pro#5127 add topic to graphql

* dbeaver/pro#5127 add topic to graphql

* adds workspace config event handler + handles drivers list

* adds workspace config event handler to connection info resource

* cleanup

* fixes bug for event handlers so it subscribes on topic

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-17 17:58:28 +02:00
sergeyteleshev 33757a96e8 dbeaver/pro#5997 reverts ripple styles for tree elements + allows to point under it (#3530) 2025-06-17 21:43:56 +08:00
Alexander Skoblikov 47a6ba4632 dbeaver/pro#4404 fix origin form k8s headers (#3527) 2025-06-17 10:40:37 +02:00
Alexey 507aa096dd dbeaver/pro#5123 feat: add welcome screen & update react-data-grid (#3513) 2025-06-17 01:03:28 +08:00
sergeyteleshevandmr-anton-t c28af2a722 dbeaver/pro#5989 removes unused styles for cloud explorer checkbox (#3525)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-16 21:57:51 +08:00
sergeyteleshevandEvgenia 1d01db34ff dbeaver/pro#5975 normalizes chunk ids (#3524)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-16 21:57:02 +08:00
Alexander Skoblikovandkseniaguzeeva 6d70e03a9e dbeaver/pro#4404 dynamic server url (#3379)
* dbeaver/pro#4404 wip

* dbeaver/pro#4404 get origin from user request

* dbeaver/pro#4404 dynamic server url

* dbeaver/pro#4404 dynamic server url

* dbeaver/pro#4404 update after merge

* dbeaver/pro#4404 fixes after devel changes

* dbeaver/pro#4404 get origin url from headers

* dbeaver/pro#4404 fix referer

* dbeaver/pro#4404 support forward headers

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-06-16 14:51:02 +02:00
serge-rider d69eb04b11 Merge remote-tracking branch 'origin/devel' into devel 2025-06-14 16:57:35 +02:00
serge-rider f891c26ee2 dbeaver/pro#5982 Remove redundant Bundle-ClassPath 2025-06-14 16:55:46 +02:00
12ef593bd7 [CB] Integrate UIKit Checkbox to Cloudbeaver #5797 (#3493)
* dbeaver/pro#5797 adds boilerplate for checkboxes (needs styles setting for CB)

* reverts ui-kit checkbox behavior

* adjusts styles

* removes _checkbox.scss

* incapsulates styles into checkboxMarkup so it does not affect ui kit checkbox

* removes unused styles

* tunes styles: margin + disabled checkbox state

* moves caption layout inside checkboxmarkup

* adds sizes styles

* сleanup

* removes unused checkbox ref + fixes styles for menu checkbox items

* adds className prop to nav bar menus

* cleanup

* moved datagrid styles to boolean formatter

* Revert "adds className prop to nav bar menus"

This reverts commit fc1cdb2f0b.

* adds approach of reusing checkbox styles (module/non-module)

* cleanup

* removes secondary from menu item renderer checkbox

* fixes checkbox bug with datagrid styles conflict

* adds BEM methodology naming for checkboxes classNames

* pr fixes

* adds checkbox sizes in booleanFormatter

* test fixes

* fixes styles for users

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-14 00:16:45 +08:00
AnastasiyaandEvgenia 3f17ec4abc dbeaver/pro#5942 update AWS update link (#3521)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-13 21:56:30 +08:00
Alexey f0010494fa dbeaver/pro#5889 fix: unit tests win (#3522) 2025-06-13 17:33:06 +08:00
5c17cc660d dbeaver/pro#5673 Add search ability for the value panel (#3511)
* dbeaver/pro#5673 feat: add search panel component and integrate search functionality

* dbeaver/pro#5673 feat: enhance search panel layout styles

* dbeaver/pro#5673 feat: reactive search panel

* dbeaver/pro#5673 refactor: separation of concerns

* dbeaver/pro#5673 refactor: make outline thinner in search panel

* dbeaver/pro#5673 feat: Add new SVG icons for match word, regex, and replace functionalities

* dbeaver/pro#5673 feat: add Icon component with customizable properties and documentation

* dbeaver/pro#5673 feat: update OrderButton and SearchPanel to use new Icon component

* dbeaver/pro#5673 feat: refactor SearchPanel layout

* dbeaver/pro#5673 refactor: remove redundant reexport

* dbeaver/pro#5673 refactor: convert SearchPanel to a MobX observer component

* dbeaver/pro#5673 refactor: remove unused searchOptions from IDefaultExtensions interface

* dbeaver/pro#5673 refactor: use useImperativeHandle for focus handling

To exclude the chance of manipulating input unexpectedly outside of the component.

* dbeaver/pro#5673 refactor: adjust padding and margin in search panel styles

* dbeaver/pro#5673 refactor: update SVG icon import to use react component

* dbeaver/pro#5673 build: update dependencies in yarn.lock

* dbeaver/pro#5673 fix: regexp

* dbeaver/pro#5673 fix: correct translation for 'No found' to 'Not found'

* dbeaver/pro#5673 refactor: remove extra regex check

* dbeaver/pro#5673 refactor: fix styles

* dbeaver/pro#5673 fix: swap arrow icons for find next and find previous buttons

* dbeaver/pro#5673 fix: adjust flex-basis for search panel matches container

* dbeaver/pro#5673 feat: add isReadOnly prop to SearchPanel

* dbeaver/pro#5673 feat: add placeholder color variables for input fields

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-13 17:22:38 +08:00
JeremyandEvgenia 41ff7485d5 feat: Add Driver for Databend (#3488)
* feat: Add Driver for Databend

* remove idea dir

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-06-13 10:12:25 +02:00
Sychev Andreyandmr-anton-t fbdb5cd49a dbeaver/pro#5800 refactor: InputFieldBase (#3492)
* dbeaver/pro#5800 refactor: InputFieldBase

update InputField by swapping native input by Input from ui-kit, replace inner action icons to IconButton components, and replace Loader with Spinner component

* dbeaver/pro#5800 fix: enforce border and min-height styles in InlineEditor

* dbeaver/pro#5800 feat: add size prop to Filter component for responsive input sizing

* dbeaver/pro#5800 feat: add UiInput tokens for input component

removes hover effect on inputs by using the same token as for default border

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-12 17:21:29 +08:00
AlexeyandDaria Marutkina c920f84e13 dbeaver/pro#4910 fix: tooltip for disabled context menu items (#3503)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-11 23:42:29 +08:00
AlexeyandDaria Marutkina 84d85ea28e dbeaver/pro#5898 chore: update navigator icons (#3497)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-10 23:10:05 +08:00
sergeyteleshevandmr-anton-t dd060e8b42 [CB] spread new ConnectionInfoResources across the app #5412 (#3501)
* dbeaver/pro#5412 removes includeAuthProperties from ConnectionInfoResource

* dbeaver/pro#5412 removes customIncludeOptions from ConnectionInfoResource

* dbeaver/pro#5412 removes includeNetworkHandlersConfig from ConnectionInfoResource

* dbeaver/pro#5412 removes includeProviderProperties from ConnectionInfoResource

* dbeaver/pro#5412 removes includeAuthNeeded & includeCredentialsSaved from ConnectionInfoResource

* dbeaver/pro#5412 removes includeProperties from ConnectionInfoResource

* cleanup

* moves some auth properties to ConnectionInfoAuthPropertiesResource

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-10 22:38:04 +08:00
Alexey 786babc988 dbeaver/pro#5889 fix: unit tests (#3515) 2025-06-10 20:33:53 +08:00
9739ab3b46 dbeaver/pro#5218 fix: limit websocket connection retry to 4 attempts (#3502)
* dbeaver/pro#5218 fix: limit websocket connection retry to 4 attempts

* Update README.md - update contribution info (#3505)

* dbeaver/pro#5910 fix: sorting only for result sets (#3506)

* dbeaver/pro#5910 fix: sorting only for result sets

* dbeaver/pro#5910 fix: require result set constraints only when needed

* dbeaver/pro#5915 Delete legacy name service API usage + code style (#3510)

* dbeaver/pro#5842 add validation for unset value (#3483)

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>

---------

Co-authored-by: Anastasiya <45152336+LonwoLonwo@users.noreply.github.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-10 19:58:46 +08:00
Serge Riderandmr-anton-t ab31ddda40 dbeaver/pro#5936 P2 repos endpoints (#3512)
* dbeaver/pro#5936 P2 repos endpoints

* dbeaver/pro#5936 Switch to new P2 repo

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-06-10 11:45:57 +02:00
alexandDaria Marutkina 08d65c4410 dbeaver/pro#5842 add validation for unset value (#3483)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-06-09 22:45:45 +08:00
Serge Rider f7cd98ae4e dbeaver/pro#5915 Delete legacy name service API usage + code style (#3510) 2025-06-06 09:38:06 +02:00
Alexey 419f8b562e dbeaver/pro#5910 fix: sorting only for result sets (#3506)
* dbeaver/pro#5910 fix: sorting only for result sets

* dbeaver/pro#5910 fix: require result set constraints only when needed
2025-06-04 22:23:19 +08:00
Anastasiya 927ba55dff Update README.md - update contribution info (#3505) 2025-06-04 13:26:44 +02:00
mayer 28aea99a3b dbeaver/dbeaver-devops#1943 base image upgrade removed (#3500) 2025-06-03 16:26:19 +02:00
Serge Rider e7c6c11342 dbeaver/pro#5738 Migrate to Tycho 4.0.12 and JDK 21 (#3494) 2025-06-03 11:56:26 +02:00
Serge Rider d2d915a8ea dbeaver/pro#5826 QM service model refactoring (#3490) 2025-06-02 16:12:03 +02:00
ShadelessFox 6b8bcfbc1a dbeaver/pro#5774 Correctly handle current working directory (#3462) 2025-06-02 13:46:28 +02:00
Daria MarutkinaandAnastasiya 31be26e167 dbeaver/pro#5832 Update README file (#3491)
* dbeaver/pro#5832 Update README file

Co-authored-by: Anastasiya <45152336+LonwoLonwo@users.noreply.github.com>
2025-06-02 12:46:28 +02:00
sergeyteleshev 9c788a56cd [CB] Use UIKit Button component for SplitControls implementation #5799 (#3489)
* dbeaver/pro#5799 moves split control to the button component

* applies ui kit css

* makes styles not moduled + cleanup

* uses theme colors + fixes prop for button

* removes unused button styles

* build fix

* build fix 2
2025-06-02 16:09:41 +08:00
Serge Rider 5bc1734cb6 dbeaver/pro#5832 25.1.1 version bump 2025-05-27 19:37:07 +02:00
aba27cf9d3 dbeaver/pro#5711 Add validation for team id (#3459)
* dbeaver/pro#5711 Add validation for team id

* dbeaver/pro#5711 Add validation for user id

* dbeaver/pro#5711 add user name and team id validation

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 17:53:09 +02:00
sergeyteleshev a098db62c3 [CB] hotkeys with "/" and "\" dont work after hotkeys library version upgrade #5781 (#3478)
* dbeaver/pro#5781 fixes shortcuts with slashes symbols + correctly translates it in the shortcut tips section

* moves display logic in SHORCUTS_DATA helpers

* adds replace all for shorcuts to consider sequential shorcuts cases

* adds formatShortcutKeys helper

* removes useless code

* adds alt -> option conversion

* refactors formatKey logic to switch

* cleanup

* cleanup

* cleanup

* switch with lowerCaseCode

* moves shortcut helpers to core-utils + uses it everywhere

* Revert "moves shortcut helpers to core-utils + uses it everywhere"

This reverts commit b4eeda5adf.
2025-05-27 17:50:17 +02:00
c4886127a6 dbeaver/pro#5821 Style fixes (#3479)
* dbeaver/pro#5821 fix: add cursor pointer to icon button

* dbeaver/pro#5821 refactor: change view button type

* dbeaver/pro#5821 feat: add UiSpinner styles for theme integration

* dbeaver/pro#5821 fix: update button class

* dbeaver/pro#5821 fix: improve buttons in driver management

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-27 17:49:05 +02:00
Alexander Skoblikovandkseniaguzeeva 343d671575 dbeaver/pro#5778 custom certs folder in conf folder (#3477)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-27 16:14:11 +02:00
AlexeyandEvgenia 06a0411f84 dbeaver/pro#5200 feat: fast connection / folder creation in the explorer (#3464)
* dbeaver/pro#5200 feat: fast connection / folder creation in the explorer

* chore: update icons

* chore: update icons

* chore: remove important from style

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 21:33:23 +08:00
ffe3d45017 dbeaver/pro#5789 replace Buttons styles (#3468)
* dbeaver/pro#5789 refactor: add ButtonIcon component instead of Button.Icon

* dbeaver/pro#5789 refactor: button components across whole application to use UIKit button and UIKit variables

- Rewrite Button.css(former button.module.css) file to define button styles for better maintainability and scalability
- Added props to the Button component for Icons: 'size' and 'placement', currently used only in PropertiesTable (Add property)
- Changed button modifiers to 'variant' swapping unelevated mod to primary(default one, so mod just deleted) and outlined mod to variant secondary.
- In one case changed raised mod to danger variant (deleting a license)

* dbeaver/pro#5789 refactor: fix Button component styling and removed redundant css file

* dbeaver/pro#5789 style: clean up button formatting across multiple components

* dbeaver/pro#5789 refactor: update Tailwind CSS import to use layer directive

* dbeaver/pro#5789 refactor[kit]: add disabled state styles for buttons

* dbeaver/pro#5789 refactor: enhance button styles for disabled state

* dbeaver/pro#5789 fix button problems

* dbeaver/pro#5789 fix: change layer name from theme to base in color styles

* dbeaver/pro#5789 refactor: update button padding from 16px to 15px

* dbeaver/pro#5789 refactor: adjust button gap and update InputFiles button props

* dbeaver/pro#5789 style: center align button in SSHKeyUploader component

* dbeaver/pro#5789 fix: update button classes to use inline-flex for better alignment

* dbeaver/pro#5789 fix: remove initial background from tab styles

* dbeaver/pro#5789 fix: move cursor pointer rule to button container

* dbeaver/pro#5789 fix: update checkbox SVG fill property for proper rendering

* dbeaver/pro#5789 fix: add variant prop to Button component for styling options

* dbeaver/pro#5789 fix: add InlineEditor to CSS layer to compete with theme Important! border-color

* dbeaver/pro#5789 fix: add min-width to button styles for consistency

* dbeaver/pro#5789 refactor: adjust margin for trigger element in context menu

first of all it's done to fix autotests and the second reason is to visually balance the cell with menu

* dbeaver/pro#5789 fix: make boolean great again

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-27 16:59:01 +08:00
ElizabethandDiana 16005be3e6 dbeaver/dbeaver#37602 Add the setting for column names completion (#3474)
* dbeaver/dbeaver#37602 Add the setting for column names completion

* dbeaver/dbeaver#37602 Fix formatting

---------

Co-authored-by: Diana <31996417+uslss@users.noreply.github.com>
2025-05-27 06:20:47 +02:00
alexandEvgenia 005adb10ce dbeaver/pro#5215 track close event on layout close (#3472)
* dbeaver/pro#5215 track close event on layout close

* dbeaver/pro#5215 support old close behaviour

* dbeaver/pro#5215 add event data check to user form

* dbeaver/pro#5215 change naming

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 00:39:06 +08:00
Sychev Andrey 0a7d9e6a25 dbeaver/pro#5814 fix: wrap checkbox styles in base layer (#3473)
* dbeaver/pro#5814 ашч: wrap checkbox styles in base layer

* dbeaver/pro#5814 style: wrap disabled styles in base layer
2025-05-26 21:24:09 +08:00
Ainur 0edfb29851 dbeaver/pro#5523 add reason for enable user log (#3463) 2025-05-26 08:31:34 +00:00
52f567fded dbeaver/pro#5553 Add Sorting functionality to base grid (#3456)
* dbeaver/pro#5553 feat: add column sorting functionality to DataGrid

* dbeaver/pro#5553 feat: enhance column sorting functionality to support multiple selection

* dbeaver/pro#5553 feat: add keyboard navigation to order button

* dbeaver/pro#5553 feat: add constraints handling logic for column sorting in DataGrid

* Revert "dbeaver/pro#5553 feat: add constraints handling logic for column sorting in DataGrid"

This reverts commit 6028a48b13.

* dbeaver/pro#5553 feat: add icon generation script to UIKit, add sample icons

* dbeaver/pro#5553 refactor: use inner react-data-grid API for column sorting

* dbeaver/pro#5553 feat: add IconCross component and update icon-related files

* dbeaver/pro#5553 feat: replace Button with IconButton in OrderButton component

* dbeaver/pro#5553 style: update foreground color variables for IconButton component

* dbeaver/pro#5553 refactor: add normalization rules to layers, use IconButton in Common DialogHeader

checked if new IconButton works well in light and dark mode by using in CommonDialogHeader

* dbeaver/pro#5553 style: format code and update dependencies in CommonDialogHeader and DataGridTable components

* dbeaver/pro#5553 style: move onColumnSort prop to correct position in DataGridTable component

* dbeaver/pro#5553 refactor: remove icons component generation, use svg sprite

* dbeaver/pro#5553 refactor: update OrderButton component and inline icons sprite in Body

we decided to go with this solution for now just adding icons to a sprite and use them by id. Imports by ?url  don't work in VSCode if try to use them in <use> href, so we need to find another solution or stick to that approach.

* dbeaver/pro#5553 refactor: update column sorting and sortable logic in DataGrid components

* dbeaver/pro#5553 style: format whitespace in Body component

* dbeaver/pro#5553 feat: add new sorting icons for ascending, descending, and unsorted states

* dbeaver/pro#5553 refactor:styling for header cell and order button components

* dbeaver/pro#5553 refactor: update sorting logic in DataGrid and OrderButton components

* dbeaver/pro#5553 refactor: value deps

* dbeaver/pro#5553 feat: update sorting icons for ascending, descending, and unsorted states

* dbeaver/pro#5553 style: update aria-label and title for OrderButton component

* dbeaver/pro#5553 fix: double focus

* dbeaver/pro#5553 fix: after merge

* dbeaver/pro#5553 refactor: removed outline offset for sort button

* dbeaver/pro#5553 refactor: update Tailwind CSS import to use layer directive

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2025-05-24 00:21:37 +08:00
Ainur 116b1a3be8 dbeaver/pro#5160 check length of meta param values (#3471) 2025-05-23 16:01:09 +02:00
AlexeyandDaria Marutkina 84cc6fcf60 dbeaver/pro#5753 feat: react-dnd (#3454)
* dbeaver/pro#5753 feat: react-dnd

* chore: fix after review

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-23 18:52:22 +08:00
1f4266ec95 dbeaver/pro#5745 [CB] Bump NPM dependencies #5745 (#3457)
* dbeaver/pro#5745 updates frontend deps

* updates graphql-request

* updates yarn locks for common-typescript, common-react

* updates engines node version

* react-hotkeys-hook + fixes hotkeys so it continues to work

* code cleanup for parseHotKey

* uses fixed version of tailwindcss

* adds 4.0.6 versions for tailwindcss with resolutions

* reverts tailwind 4.0.6 version for yarn.lock

* removes redundant resolutions for tailwindcss

* Update readme.md with new NodeJS version

* Update README.md with correct nodejs version according to our documentation

* updates talewindcss version 4.0.7

* fix: hotkeys types

---------

Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-05-23 17:31:13 +08:00
Alexey c85b3ccd24 dbeaver/pro#5779 fix: external app plugin naming (#3467) 2025-05-22 17:05:18 +02:00
Ruslan MusaevandEvgenia 7687943ecf dbeaver/pro#5649 Do not send update event if a user teams are same (#3453)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-22 11:14:21 +02:00
alexandEvgenia 587d25bb40 dbeaver/pro#5709 close panel before deleting user (#3458)
* dbeaver/pro#5709 close panel before deleting user

* dbeaver/pro#5709 bump licence year

* dbeaver/pro#5709 remove unnecessary resource hook

* dbeaver/pro#5709 remove unused import

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-22 16:48:42 +08:00
5561d37ce8 dbeaver/pro#4888 Ldap support ssl (#3438)
* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 fix connection on TE

* dbeaver/pro#4888 ldaps fix

* fix: check configuration id for auth token

* dbeaver/pro#4888 one authentication per provider and configuration

* dbeaver/pro#4888 one authentication per provider and configuration

* Revert "fix: check configuration id for auth token"

This reverts commit 517cc717a8.

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Wroud <wrouds@gmail.com>
2025-05-21 12:26:11 +02:00
alexandkseniaguzeeva fffbea22af dbeaver/pro#5458 add toggleDisabled setting (#3455)
* dbeaver/pro#5458 add toggleDisabled setting

* dbeaver/pro#5458 change setting name

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-21 17:39:50 +08:00
Ainur 934d45617a dbeaver/pro#4372 add new attribute for a property group (#3461) 2025-05-20 18:13:38 +02:00
Ainur ccb6f2208c dbeaver/pro#5404 add complex auth servlet handler (#3418) 2025-05-20 14:33:40 +00:00
alexandDaria Marutkina d9e4383b22 dbeaver/pro#5382 fallback undefined to false (#3452)
* dbeaver/pro#5382 fallback undefined to false

* dbeaver/pro#5382 bump year

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-20 16:34:18 +08:00
Ruslan MusaevandEvgenia cbd8458776 dbeaver/pro#5638 Multi team mapping (#3441)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:59 +02:00
Ruslan MusaevandEvgenia 3352b66a26 dbeaver/pro#5694 Fix auth providers init (#3442)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:27 +02:00
Ruslan MusaevandEvgenia 9b5ceed501 dbeaver/pro#5693 Fix ldap bruteforce protection (#3446)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:02 +02:00
alexandDaria Marutkina 3687a0807d dbeaver/pro#5678 use new api command (#3440)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-19 15:29:30 +02:00
sergeyteleshevandDaria Marutkina bda9966330 dbeaver/pro#5561 removes tiny style from checkboxes for AuthModelCredentialsForm (#3445)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-19 19:39:19 +08:00
Sychev Andreyandmr-anton-t f0be7b6af6 dbeaver/pro#5554 [CB] [UI kit] create IconButton component (#3424)
* dbeaver/pro#5554 feat: first iteration of IconButton

* dbeaver/pro#5554 refactor: css var changes

* dbeaver/pro#5554 feat: add loading state to IconButton component

* dbeaver/pro#5554 style: update background color for loading state in IconButton

* dbeaver/pro#5554 feat: separate icon button styles and loader variables

* dbeaver/pro#5554 refactor: extract ButtonRoot component to use as a base for Button and IconButton components

That approach lets us use common logic (loading) but don't mixup styles and tokens and have better control

* dbeaver/pro#5554 refactor: update loading state styles for IconButton component

* dbeaver/pro#5554 refactor: ButtonRootProps

* dbeaver/pro#5554 refactor: remove opacity from loading state in Button and IconButton components

* dbeaver/pro#5554 refactor: create content wrapper, move general styles there, add loader wrapper

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-05-19 19:38:30 +08:00
serge-rider 3b0f0ddf1e Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2025-05-19 11:44:14 +02:00
serge-rider 85526b45dd Revert "dbeaver/dbeaver#37928 Downgrade ClickHouse driver to 0.7.2 (#3447)"
This reverts commit 7a48102df4.
2025-05-19 11:42:15 +02:00
Daria Marutkina a6a7aeb97f dbeaver/pro#5684 Update README file (#3451)
* dbeaver/pro#5684 Update README file
2025-05-19 11:14:21 +02:00
serge-rider edf54d3b72 dbeaver/pro#5668 Annotations 2025-05-18 10:07:17 +02:00
ShadelessFox 7a48102df4 dbeaver/dbeaver#37928 Downgrade ClickHouse driver to 0.7.2 (#3447) 2025-05-17 05:14:19 +02:00
Ruslan Musaev a16d03d5a6 dbeaver/pro#5695 Revert "Add Driver for Databend (#3174)" (#3443) 2025-05-15 11:12:01 +02:00
serge-rider 8410df4fa9 dbeaver/pro#5684 25.1.0 version bump 2025-05-13 19:23:55 +02:00
295fcf8701 dbeaver/pro#5087 feat: gql api (#3400)
* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 feat: gql api

* dbeaver/pro#5087 feat: gql api

* dbeaver/pro#5087 Add role settings

* feat: user role settings

* chore: add tailwind intellisense

* chore: remove mock data

* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 Add role settings

* fix: update roles enum

* feat: settings restore and set status

* dbeaver/pro#5087 fix roles

* chore: hide single settings tab, allow reset for settings that doesn't support full reset

* chore: remove `isSet` method from settings API

* refactor: extract repeatable logic

* chore: add server setting

* chore: better settings grouping

* dbeaver/pro#5087 fixes

* fix: review

* chore: remove roles related code

* chore: hide spreadsheet hiding setting

* dbeaver/pro#5087 Removed everything related with authRole

* chore: hide some settings from UI

* chore: hide per-setting reset

* fix: selecting empty settings groups

---------

Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-14 00:01:08 +08:00
Ruslan MusaevandDaria Marutkina ba4f1c9db7 Dbeaver/pro#5652 add security to endpoints (#3435)
* dbeaver/pro#5652 add security to endpoints

* dbeaver/pro#5652 add security to endpoints

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 23:59:39 +08:00
Sychev AndreyandDaria Marutkina bde5c93740 dbeaver/pro#5599 refactor: simplify manualChunks function (#3436)
* dbeaver/pro#5599 refactor: simplify manualChunks function by removing async and circular dependency check

* Revert "dbeaver/pro#5599 refactor: simplify manualChunks function by removing async and circular dependency check"

This reverts commit a8faed50fa.

* dbeaver/pro#5599 fix: configure Vite to prevent CSS code splitting

* dbeaver/pro#5599 refactor: move splitting setting to plugin, add comment

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 20:49:39 +08:00
Pat BuxtonandDaria Marutkina 2421e4806a dbeaver/cloudbeaver#3174 Add Driver for Databend (#3175)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 12:59:02 +02:00
27a9cf3d58 dbeaver/pro#4958 Add default catalog and default schema (#3420)
* dbeaver/pro#4958 Add default catalog and default schema

* dbeaver/pro#4958 add catalog and schema

* dbeaver/pro#4958 remove field duplication

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 12:56:12 +02:00
sergeyteleshev cddbb1c876 dbeaver/pro#5377 adds redownload button for drivers installation (#3432) 2025-05-12 22:21:42 +08:00
sergeyteleshevandEvgenia 2ab9d2f450 dbeaver/pro#5405 adds autosave for scripts (#3427)
* dbeaver/pro#5405 adds autosave for scripts

* fixes russian locale

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-12 22:21:21 +08:00
alex 750d66c4ae dbeaver/pro#4405 return version update styles (#3434)
* dbeaver/pro#4405 return version update styles

* dbeaver/pro#4405 fix styles in docker instruction
2025-05-12 22:21:04 +08:00
Ainur 844c01dc75 Revert "dbeaver/pro#5214 get timestamp with calendar fix (#3423)" (#3431)
* Revert "dbeaver/pro#5214 get timestamp with calendar fix (#3423)"

This reverts commit 7b0c6ebe66.

* Revert "dbeaver/pro#5214 set timestamp with utc calendar fix (#3404)"

This reverts commit 0095cc8d37.
2025-05-08 16:25:14 +02:00
154082e6bd vietnamese-localization (#3395)
* vietnamese-localization

* dbeaver/pro#3395 remove extra files

* dbeaver/pro#3395 remove tokens duplication

* dbeaver/pro#3395 fix formatting

* dbeaver/pro#3395 add locale on the backend

* dbeaver/pro#3395 add hardcoded ordering

---------

Co-authored-by: hanhvd <hanhvd@gmail.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
2025-05-08 16:21:35 +02:00
sergeyteleshevandDaria Marutkina 5d90858fa3 prevents default behavior if shortcut executed in it is own scope #3402 (#3417)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-08 14:43:10 +02:00
Sychev AndreyandEvgenia 0ae505fd32 dbeaver/pro#5497 fix: update disabled state logic in BooleanFormatter (#3425)
* dbeaver/pro#5497 fix: update disabled state logic in BooleanFormatter

* dbeaver/pro#5497 style: format disabled state logic

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-08 19:34:39 +08:00
AinurandDaria Marutkina 7b0c6ebe66 dbeaver/pro#5214 get timestamp with calendar fix (#3423)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-08 11:50:02 +02:00
Sychev AndreyandDaria Marutkina 591083435d 5490 cb create spinner UI kit component (#3415)
* #5490 feat: create basic spin component

* #5490 refactor: use new Spin component in button loading state

* #5490 refactor: add tokens to Spin component

add SpecialLoader story to show how to change Spin appearance for special use cases

* #5490 fix: reverts f4d9b6b101

Element should not get focus visible after mouse interactions

* 5490 fix: lost dash

* #5490 refactor: rename Spin to Spinner

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-07 16:23:06 +02:00
d23959a9b5 dbeaver/pro#5460 Add redirect field to provider creation form (#3409)
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-07 15:33:36 +02:00
Ruslan MusaevandEvgenia 1799768389 dbeaver/pro#5542 change ldap uuid to cn or login (#3410)
* dbeaver/pro#5542 change ldap uuid to cn or login

* dbeaver/pro#5542 fixes

* dbeaver/pro#5542 fixes

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-07 15:14:18 +02:00
Alexey 250547f329 dbeaver/cloudbeaver#3402 fix: yarn.lock (#3422) 2025-05-07 16:10:58 +08:00
Georgii 4f52c445fc dbeaver/pro#4075 fix naming (#3416)
* dbeaver/pro#4075 fix naming

* dbeaver/pro#4075 fix rmnio

* dbeaver/pro#4075 fix test launch

* dbeaver/pro#4075 fix test launch
2025-05-06 20:48:40 +02:00
0c70890258 dbeaver/pro#4066 run cli client from launcher, add cli server to CB (#3352)
* dbeaver/pro#4066 run cli client from launcher, add cli server to CB

* dbeaver/pro#4066 special scripts to execute cli commands

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-06 20:47:36 +02:00
Sychev AndreyandAlexey bc656de886 #3389 docs: update cb webapp readme (#3399)
* #3389 docs: update cb webapp readme

* #3389 docs: add part about node.js

* #3389 docs: add section about VSCode

* #3389 docs: add OS-specific instructions

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2025-05-06 23:06:37 +08:00
alexandDaria Marutkina fb6e6f6f13 dbeaver/pro#5593 move property value getter to common place (#3414)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 22:26:19 +08:00
a0d79ff9b1 dbeaver/pro#5480 Fixed unauthorized access to ldap (#3381)
* dbeaver/pro#5480 Fixed unauthorized access to ldap

* dbeaver/pro#5480 Unauthorized attempt to fetch ldaps groups

* dbeaver/pro#5480 unauthorize attempt to fetch ldaps groups

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mayer <57711367+mayerro@users.noreply.github.com>
2025-05-06 14:25:06 +02:00
f5dfd8726a dbeaver/pro#5312 chore: update typescript sdk (#3407)
* dbeaver/pro#5312 chore: update typescript sdk

* dbeaver/pro#5312 chore: update eslint config

* dbeaver/pro#5312 chore: delete unused file

* dbeaver/pro#5572 remove deprecated annotations (#3405)

* Markup fix (#3408)

* dbeaver/pro#5588 25.0.5 version bump

* #5509 fix: checkbox doesn't get focused on click (#3406)

* dbeaver/pro#5588 Update README file (#3412)

---------

Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: serge-rider <serge@dbeaver.com>
Co-authored-by: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 18:09:45 +08:00
AinurandDaria Marutkina 0095cc8d37 dbeaver/pro#5214 set timestamp with utc calendar fix (#3404)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 10:04:00 +02:00
Daria Marutkina 16fcc21346 dbeaver/pro#5588 Update README file (#3412) 2025-05-05 11:27:23 +02:00
Sychev Andrey f5e4f14159 #5509 fix: checkbox doesn't get focused on click (#3406) 2025-05-05 15:24:34 +08:00
serge-rider 0c1d47ef10 dbeaver/pro#5588 25.0.5 version bump 2025-05-05 07:33:25 +02:00
Serge Rider 2d82e85491 Markup fix (#3408) 2025-04-30 12:27:09 +02:00
Alexander Skoblikov 87e9c79e43 dbeaver/pro#5572 remove deprecated annotations (#3405) 2025-04-30 08:31:20 +00:00
Serge Rider c3042d5aa4 dbeaver/pro#5588 25.0.5 version bump 2025-04-29 19:43:34 +02:00
1121 changed files with 22113 additions and 14525 deletions
+19
View File
@@ -19,6 +19,16 @@
"group": "test",
"args": ["test"]
},
{
"label": "Run Tests Common Typescript",
"type": "shell",
"command": "yarn",
"group": "test",
"args": ["test"],
"options": {
"cwd": "${workspaceFolder}/common-typescript"
}
},
{
"label": "Run DevServer CE",
"group": "build",
@@ -107,6 +117,15 @@
"options": {
"cwd": "${workspaceFolder}/webapp/packages"
}
},
{
"label": "Run Ui Kit Preview",
"type": "shell",
"command": "yarn",
"options": {
"cwd": "${workspaceFolder}/common-react/@dbeaver/ui-kit"
},
"args": ["docs"]
}
],
"inputs": [
+43 -49
View File
@@ -7,7 +7,7 @@ CloudBeaver is a web server that provides a rich web interface. The server itsel
It is free to use and open-source (licensed under [Apache 2](https://github.com/dbeaver/cloudbeaver/blob/devel/LICENSE) license).
See our [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/>
<a><img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/></a>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/gis-demo.png" width="400"/>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/data-transfer-demo.png" width="400"/>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/sql-editor-demo.png" width="400"/>
@@ -25,62 +25,56 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
### 25.0.3 2025-04-21
- Administration: log records now capture create, update, and delete actions for users, teams, and connections for improved tracking and transparency;
- SQL Editor: auto-completion has been improved for aliases and camelCase entities;
- Users DDL in Oracle is displayed in metadata editor on corresponding tab for users with Oracle administration permissions;
- Different bug fixes and enhancements have been made.
### 25.1.3 2025-07-21
- A password confirmation field has been added for administrators in the Easy Config section to help prevent accidental misconfigurations;
- Added column descriptions in the Data Editor to provide more metadata context. You can disable this in Preferences > Data Viewer;
- Added the option to display tabs across multiple rows, allowing you to see all tabs without scrolling. You can enable this in Preferences > Interface;
- Changed the default engine used for autocompletion in the SQL Editor. This Semantic engine offers improved suggestions for database objects, keywords, and functions. You can switch back to the Legacy engine in Preferences -> SQL Editor;
- Clickhouse: fixed the presentation of tuples and map data types in the data editor.
### 25.1.2 2025-07-07
- The CloudBeaver default theme matches the device theme by default now. You can change this behavior in user preferences under the Theme section;
- Added a button “Clear” to the Output panel;
- Changed the data transfer mechanism to avoid intermediate file creation. The parameter dataExportFileSizeLimit was removed from the server configuration as deprecated;
- PostgresSQL: fixed misplaced comment for table DDL generation.
### 25.0.2 2025-04-07
- Data Editor: improved table rendering to scale column width depending on the content.
- Improved Navigation tree performance: lost connection does not lead to the application freezing anymore.
- Different bug fixes and enhancements have been made.
### 25.1.1 2025-06-23
### Changes since 25.1.0:
- Added a search panel for SQL Editor and Value panel: press Ctrl+F to open a panel that allows searching and replacing by keyword or regular expression.
- Added a new welcome screen for a freshly opened application. This screen contains shortcuts to create a new connection, open SQL editor or documentation.
- Databend database support has been added.
### 25.0.1 2025-03-24
- Improved performance of the export/import functionality by optimizing disk memory consumption;
- Enhanced initial configuration on stage security: if the initial setup time exceeds 1 hour, the server must be restarted.
### 25.0 2025-03-03
### Changes since 24.3.0:
- General:
- Added transaction log viewing for connections with manual commit mode. This allows users to see all modifying statements before committing;
- Added an ability for all editors to reconnect if a connection has been lost;
- Tooltips for metadata objects and SQL Editor tabs now include additional details about catalogs, schemas, and connections;
- Added Ctrl + Shift + S (Cmd + Shift + S on Mac) shortcut for the "Save As Script" action;
- Updated list of available shortcuts for macOS.
### 25.1.0 2025-06-02
### Changes since 25.0.0:
- Important:
- Connection templates were removed from the application. You can use the Connection Editor to create new connections.
- Administration:
- Added system information data to the Product Information tab in the Administration panel. This provides administrators with quick access to essential system details, such as the server deployment type (e.g., Docker, Kubernetes), install path, Java version, and Java parameters;
- The global access server URL has been added to the console log, making it easier to locate server installation information directly within the logs;
- New environment variables were introduced for theme styling, SQL editor, and log viewer settings. You can use them for quick setup during the initial Docker configuration stage.
- Log records now capture create, update, and delete actions for users, teams, and connections for improved tracking and transparency.
- LDAP authorization:
- Added the ability to match users from LDAP configuration with CloudBeaver users;
- Added an option to specify a user login as an attribute parameter for LDAP providers;
- CloudBeaver now uses EntityID or objectGUID to create new LDAP users in CloudBeaver to ensure uniqueness. This change enhances user identification and prevents conflicts while maintaining backward compatibility for existing users.
- Deployment:
- CloudBeaver now uses JDK 21 as its base Java image. If you use standard deployment and upgrade scripts, the new Java version will be applied automatically after the product update;
- Changed the permission of the Docker volumes directory to enhance security and prevent any insecure actions by the "root" user. All new deployments will use the "dbeaver" user by default. For existing deployments running as the "root" user, this update will automatically adjust file permissions to ensure they are compatible with the new security model. There will be no manual intervention, and the service will continue to run as expected with the updated permissions.
- Connections:
- Enabled the possibility of switching a database connection to read-only mode. This mode can be activated in the connection dialog. Administrators can set this mode for any connection, while regular users can set it for their private connections only;
- For Oracle and SQL Server connections, advanced database settings can now be used in the URL connection mode.
- Added support for secure [LDAP authentication over SSL](https://github.com/dbeaver/cloudbeaver/wiki/LDAP-Authentication);
- Brute force protection is now supported for LDAP authentication. All authentication methods on the application level have this security mechanism.
- SQL Editor:
- A new setting to autosave scripts in the SQL editor appeared in global and users' preferences;
- Auto-completion has been improved for aliases and camelCase entities.
- Data Editor:
- Auto-suggestions for column names in the Data Editor filter field were introduced to avoid typing mistakes;
- Introduced the ability to insert data in tables without unique keys: you can import data from CSV files or insert entire rows directly via UI;
- The collapse of the grouping panel doesn't lead to the complete panel cleaning anymore.
- Data transfer:
- Added the ability to use default spreadsheet names (e.g. Sheet0, Sheet1) for exporting to XLSX;
- An option to replace line break characters on any custom value was added when exporting to CSV.
- Navigator tree:
- An option to show metadata object comments was added. You can enable it in the database navigator settings panel;
- Introduced the ability to create connections not only on the initial level but in folders and sub-folders directly;
- Fixed the display of objects with long names (more than 32 characters) - now, such names will be displayed entirely and not in a cropped format.
- Drivers:
- The MariaDB driver has been updated to version 3.5.1;
- The SQLite driver has been updated to version 3.48.0.0.
- Improved table rendering to scale column width depending on the content;
- Accessibility: improved keyboard navigation by sorting buttons in column headers.
- General:
- Added the ability to configure the default database or schema in the connection configuration;
- Enhanced initial configuration stage security: a server needs to be restarted if the initial setup time exceeds 1 hour;
- Improved Navigation tree performance: lost connection does not lead to the application freezing anymore;
- Data transfer: Improved export/import functionality performance by optimizing disk memory consumption;
- Vietnamese localization has been added (thanks to [0xhanh](https://github.com/0xhanh)).
- Databases and drivers:
- Clickhouse: driver has been updated to version 0.8.5;
- DuckDB: expanded the list of system objects that can be hidden in the Navigation tree;
- LibSQL: added the ability to connect using token authentication;
- Oracle: users' DDL in Oracle is displayed in the metadata editor on the corresponding tab for users with Oracle administration permissions;
- SQLite: added information about a table's Strict mode to the table metadata section (thanks to [eusebe-cda](https://github.com/eusebe-cda)).
## Contribution
As a community-driven open-source project, we warmly welcome contributions through GitHub pull requests.
[We are happy to reward](https://dbeaver.com/help-dbeaver/) our most active contributors every major sprint.
The most significant contribution to our code for the major release 24.3.0 was made by:
1. [cashlifei](https://github.com/cashlifei)
The most significant contribution to our code for the major release 25.1.0 was made by:
1. [0xhanh](https://github.com/0xhanh) - for Vietnamese localization.
+8 -6
View File
@@ -1,9 +1,17 @@
# artifacts
lib
out
dist
node_modules
# Yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/sdks/**
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
@@ -11,9 +19,3 @@
#!.yarn/cache
.pnp.*
# artifacts
lib
out
dist
node_modules
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "prettier",
"version": "3.5.1-sdk",
"version": "3.6.2-sdk",
"main": "./index.cjs",
"type": "commonjs",
"bin": "./bin/prettier.cjs"
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, register} = require(`module`);
const {resolve} = require(`path`);
const {pathToFileURL} = require(`url`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
const absRequire = createRequire(absPnpApiPath);
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/bin/tsserver
require(absPnpApiPath).setup();
if (isPnpLoaderEnabled && register) {
register(pathToFileURL(absPnpLoaderPath));
}
}
}
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
? exports => absRequire(absUserWrapperPath)(exports)
: exports => exports;
// Defer to the real typescript/bin/tsserver your application uses
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`));
-10
View File
@@ -1,10 +0,0 @@
{
"name": "typescript",
"version": "5.7.3-sdk",
"main": "./lib/typescript.js",
"type": "commonjs",
"bin": {
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@
Root;
}
.mlln6zg7-0-0-beta-50 {
.mlln6zg7-0-0-beta-55 {
@layer rdg.MeasuringCell {
contain: strict;
grid-row: 1;
@@ -24,7 +24,7 @@
}
.cj343x07-0-0-beta-50 {
.cj343x07-0-0-beta-55 {
@layer rdg.Cell {
/* max-content does not work with size containment
* dynamically switching between different containment styles incurs a heavy relayout penalty
@@ -53,7 +53,7 @@
}
}
.csofj7r7-0-0-beta-50 {
.csofj7r7-0-0-beta-55 {
@layer rdg.Cell {
position: sticky;
/* Should have a higher value than 0 to show up above unfrozen cells */
@@ -66,8 +66,33 @@
}
}
.ch2wcw87-0-0-beta-55 {
@layer rdg.DragHandle {
--rdg-drag-handle-size: 8px;
z-index: 0;
cursor: move;
inline-size: var(--rdg-drag-handle-size);
block-size: var(--rdg-drag-handle-size);
background-color: var(--rdg-selection-color);
place-self: end;
.c1bn88vv7-0-0-beta-50 {
&:hover {
--rdg-drag-handle-size: 16px;
border: 2px solid var(--rdg-selection-color);
background-color: var(--rdg-background-color);
}
}
}
.c1wvphzh7-0-0-beta-55 {
@layer rdg.DragHandle {
z-index: 1;
position: sticky;
}
}
.c1bn88vv7-0-0-beta-55 {
@layer rdg.CheckboxInput {
display: block;
margin: auto;
@@ -86,13 +111,13 @@
}
.g1s9ylgp7-0-0-beta-50 {
.g1s9ylgp7-0-0-beta-55 {
@layer rdg.GroupCellContent {
outline: none;
}
}
.cz54e4y7-0-0-beta-50 {
.cz54e4y7-0-0-beta-55 {
@layer rdg.GroupCellCaret {
margin-inline-start: 4px;
stroke: currentColor;
@@ -107,13 +132,13 @@
}
.h44jtk67-0-0-beta-50 {
.h44jtk67-0-0-beta-55 {
@layer rdg.SortableHeaderCell {
display: flex;
}
}
.hcgkhxz7-0-0-beta-50 {
.hcgkhxz7-0-0-beta-55 {
@layer rdg.SortableHeaderCellName {
flex-grow: 1;
overflow: clip;
@@ -122,69 +147,33 @@
}
.c6ra8a37-0-0-beta-50 {
.c6ra8a37-0-0-beta-55 {
@layer rdg.Cell {
background-color: #ccccff;
}
}
.cq910m07-0-0-beta-50 {
@layer rdg.Cell {
background-color: #ccccff;
&.c6ra8a37-0-0-beta-50 {
background-color: #9999ff;
}
}
}
.c1w9bbhr7-0-0-beta-50 {
@layer rdg.DragHandle {
--rdg-drag-handle-size: 8px;
z-index: 0;
cursor: move;
inline-size: var(--rdg-drag-handle-size);
block-size: var(--rdg-drag-handle-size);
background-color: var(--rdg-selection-color);
place-self: end;
&:hover {
--rdg-drag-handle-size: 16px;
border: 2px solid var(--rdg-selection-color);
background-color: var(--rdg-background-color);
}
}
}
.c1creorc7-0-0-beta-50 {
@layer rdg.DragHandle {
z-index: 1;
position: sticky;
}
}
.cis5rrm7-0-0-beta-50 {
.cis5rrm7-0-0-beta-55 {
@layer rdg.EditCell {
padding: 0;
}
}
.c6l2wv17-0-0-beta-50 {
.c6l2wv17-0-0-beta-55 {
@layer rdg.HeaderCell {
cursor: pointer;
}
}
.c1kqdw7y7-0-0-beta-50 {
.c1kqdw7y7-0-0-beta-55 {
@layer rdg.HeaderCell {
touch-action: none;
}
}
.r1y6ywlx7-0-0-beta-50 {
.r1y6ywlx7-0-0-beta-55 {
@layer rdg.HeaderCell {
cursor: col-resize;
position: absolute;
@@ -195,16 +184,29 @@
}
}
.c1bezg5o7-0-0-beta-50 {
opacity: 0.5;
.c1bezg5o7-0-0-beta-55 {
@layer rdg.HeaderCell {
background-color: var(--rdg-header-draggable-background-color);
}
}
.c1vc96037-0-0-beta-50 {
background-color: var(--rdg-header-draggable-background-color);
.c1vc96037-0-0-beta-55 {
@layer rdg.HeaderCell {
background-color: var(--rdg-header-draggable-background-color);
}
}
.d8rwc9w7-0-0-beta-55 {
@layer rdg.HeaderCell {
border-radius: 4px;
width: fit-content;
outline: 2px solid hsl(207, 100%, 50%);
outline-offset: -2px;
}
}
.r1upfr807-0-0-beta-50 {
.r1upfr807-0-0-beta-55 {
@layer rdg.Row {
display: contents;
background-color: var(--rdg-background-color);
@@ -223,14 +225,14 @@
}
}
.r190mhd37-0-0-beta-50 {
.r190mhd37-0-0-beta-55 {
@layer rdg.FocusSink {
outline: 2px solid var(--rdg-selection-color);
outline-offset: -2px;
}
}
.r139qu9m7-0-0-beta-50 {
.r139qu9m7-0-0-beta-55 {
@layer rdg.FocusSink {
&::before {
content: '';
@@ -244,26 +246,26 @@
}
.h10tskcx7-0-0-beta-50 {
.h10tskcx7-0-0-beta-55 {
@layer rdg.HeaderRow {
display: contents;
background-color: var(--rdg-header-background-color);
font-weight: bold;
& > .cj343x07-0-0-beta-50 {
& > .cj343x07-0-0-beta-55 {
/* Should have a higher value than 1 to show up above regular cells and the focus sink */
z-index: 2;
position: sticky;
}
& > .csofj7r7-0-0-beta-50 {
& > .csofj7r7-0-0-beta-55 {
z-index: 3;
}
}
}
.a3ejtar7-0-0-beta-50 {
.a3ejtar7-0-0-beta-55 {
@layer rdg.SortIcon {
fill: currentColor;
@@ -274,7 +276,7 @@
}
.rnvodz57-0-0-beta-50 {
.rnvodz57-0-0-beta-55 {
@layer rdg.Defaults {
*,
*::before,
@@ -285,7 +287,7 @@
@layer rdg.Root {
--rdg-color: #000; --rdg-border-color: #ddd; --rdg-summary-border-color: #aaa; --rdg-background-color: hsl(0deg 0% 100%); --rdg-header-background-color: hsl(0deg 0% 97.5%); --rdg-header-draggable-background-color: hsl(0deg 0% 90.5%); --rdg-row-hover-background-color: hsl(0deg 0% 96%); --rdg-row-selected-background-color: hsl(207deg 76% 92%); --rdg-row-selected-hover-background-color: hsl(207deg 76% 88%); --rdg-checkbox-focus-color: hsl(207deg 100% 69%);
--rdg-selection-color: #66afe9;
--rdg-selection-color: hsl(207, 75%, 66%);
--rdg-font-size: 14px;
--rdg-cell-frozen-box-shadow: 2px 0 5px -2px rgba(136, 136, 136, 0.3);
@@ -334,30 +336,30 @@
}
> :nth-last-child(1 of .rdg-top-summary-row) {
> .cj343x07-0-0-beta-50 {
> .cj343x07-0-0-beta-55 {
border-block-end: 2px solid var(--rdg-summary-border-color);
}
}
> :nth-child(1 of .rdg-bottom-summary-row) {
> .cj343x07-0-0-beta-50 {
> .cj343x07-0-0-beta-55 {
border-block-start: 2px solid var(--rdg-summary-border-color);
}
}
}
}
.vlqv91k7-0-0-beta-50 {
.vlqv91k7-0-0-beta-55 {
@layer rdg.Root {
user-select: none;
& .r1upfr807-0-0-beta-50 {
& .r1upfr807-0-0-beta-55 {
cursor: move;
}
}
}
.f1lsfrzw7-0-0-beta-50 {
.f1lsfrzw7-0-0-beta-55 {
@layer rdg.FocusSink {
grid-column: 1/-1;
pointer-events: none;
@@ -366,7 +368,7 @@
}
}
.f1cte0lg7-0-0-beta-50 {
.f1cte0lg7-0-0-beta-55 {
@layer rdg.FocusSink {
/* Should have a higher value than 3 to show up above header and summary rows */
z-index: 3;
@@ -374,7 +376,7 @@
}
.s8wc6fl7-0-0-beta-50 {
.s8wc6fl7-0-0-beta-55 {
@layer rdg.SummaryCell {
inset-block-start: var(--rdg-summary-row-top);
inset-block-end: var(--rdg-summary-row-bottom);
@@ -382,42 +384,42 @@
}
.skuhp557-0-0-beta-50 {
.skuhp557-0-0-beta-55 {
@layer rdg.SummaryRow {
> .cj343x07-0-0-beta-50 {
> .cj343x07-0-0-beta-55 {
position: sticky;
}
}
}
.tf8l5ub7-0-0-beta-50 {
.tf8l5ub7-0-0-beta-55 {
@layer rdg.SummaryRow {
> .cj343x07-0-0-beta-50 {
> .cj343x07-0-0-beta-55 {
z-index: 2;
}
> .csofj7r7-0-0-beta-50 {
> .csofj7r7-0-0-beta-55 {
z-index: 3;
}
}
}
.g1yxluv37-0-0-beta-50 {
.g1yxluv37-0-0-beta-55 {
@layer rdg.GroupedRow {
&:not([aria-selected='true']) {
background-color: var(--rdg-header-background-color);
}
> .cj343x07-0-0-beta-50:not(:last-child, .csofj7r7-0-0-beta-50),
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-50) {
> .cj343x07-0-0-beta-55:not(:last-child, .csofj7r7-0-0-beta-55),
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-55) {
border-inline-end: none;
}
}
}
.t7vyx3i7-0-0-beta-50 {
.t7vyx3i7-0-0-beta-55 {
@layer rdg.TextEditor {
appearance: none;
File diff suppressed because one or more lines are too long
@@ -1,17 +1,17 @@
{
"name": "react-data-grid",
"version": "7.0.0-beta.50",
"version": "7.0.0-beta.55",
"type": "module",
"exports": {
"./lib/styles.css": "./lib/styles.css",
".": {
"types": "./lib/index.d.ts",
"default": "./lib/bundle.js"
"default": "./lib/index.js"
}
},
"browser": "./lib/bundle.js",
"main": "./lib/bundle.js",
"module": "./lib/bundle.js",
"browser": "./lib/index.js",
"main": "./lib/index.js",
"module": "./lib/index.js",
"types": "./lib/index.d.ts",
"files": [
"lib"
@@ -24,7 +24,7 @@
"!lib/tests",
"!.tsbuildinfo"
],
"packageManager": "yarn@4.6.0",
"packageManager": "yarn@4.9.2",
"devDependencies": {
"@dbeaver/tsconfig": "workspace:^",
"@types/react": "^19",
@@ -33,6 +33,7 @@
"typescript": "^5"
},
"dependencies": {
"@dbeaver/react-dnd": "workspace:^",
"@dbeaver/ui-kit": "workspace:^",
"react": "^19",
"react-data-grid": "file:./artifacts",
@@ -4,19 +4,29 @@ import { DataGridCellContext, type IDataGridCellRenderer } from './DataGridCellC
import { createCellMouseEvent } from './eventUtils.js';
import { DataGridCellInnerContext, type IDataGridCellInnerContext } from './DataGridCellInnerContext.js';
import { useGridReactiveValue } from './useGridReactiveValue.js';
import { HeaderDnDContext } from './useHeaderDnD.js';
export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRendererProps<TRow, TSummaryRow>) {
const cellContext = use(DataGridCellContext);
const tooltip = useGridReactiveValue(cellContext?.cellTooltip, props.rowIdx, props.column.idx);
const dndContext = use(HeaderDnDContext)!;
const virtualColIdx = props.column.idx;
const dataColIdx = dndContext.getDataColIdx(props.column.idx);
const rowIdx = props.rowIdx;
const tooltip = useGridReactiveValue(cellContext?.cellTooltip, rowIdx, dataColIdx);
function handleClick(event: React.MouseEvent<HTMLDivElement>) {
props.onClick?.(
props.onCellClick?.(
{
rowIdx: props.rowIdx,
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx: props.rowIdx, idx: props.column.idx }, enableEditor);
props.selectCell(
{ rowIdx, idx: virtualColIdx },
{
enableEditor,
},
);
},
},
createCellMouseEvent(event),
@@ -24,13 +34,13 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
}
function handleDoubleClick(event: React.MouseEvent<HTMLDivElement>) {
props.onDoubleClick?.(
props.onCellDoubleClick?.(
{
rowIdx: props.rowIdx,
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx: props.rowIdx, idx: props.column.idx }, enableEditor);
props.selectCell({ rowIdx, idx: virtualColIdx }, { enableEditor });
},
},
createCellMouseEvent(event),
@@ -38,13 +48,13 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
}
function handleContextMenu(event: React.MouseEvent<HTMLDivElement>) {
props.onContextMenu?.(
props.onCellContextMenu?.(
{
rowIdx: props.rowIdx,
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx: props.rowIdx, idx: props.column.idx }, enableEditor);
props.selectCell({ rowIdx, idx: virtualColIdx }, { enableEditor });
},
},
createCellMouseEvent(event),
@@ -52,7 +62,16 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
}
const mappedProps = useMemo(
() => ({ ...props, isFocused: props.isCellSelected, onClick: handleClick, onDoubleClick: handleDoubleClick, onContextMenu: handleContextMenu }),
() => ({
...props,
onCellClick: undefined,
onCellContextMenu: undefined,
onCellDoubleClick: undefined,
isFocused: props.isCellSelected,
onClick: handleClick,
onDoubleClick: handleDoubleClick,
onContextMenu: handleContextMenu,
}),
Object.values(props),
);
@@ -63,9 +82,9 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
<Cell
{...props}
title={tooltip}
onClick={(_, event) => onClick?.(event)}
onDoubleClick={(_, event) => onDoubleClick?.(event)}
onContextMenu={(_, event) => onContextMenu?.(event)}
onCellClick={(_, event) => onClick?.(event)}
onCellDoubleClick={(_, event) => onDoubleClick?.(event)}
onCellContextMenu={(_, event) => onContextMenu?.(event)}
{...rest}
isCellSelected={props.isCellSelected || rest.isFocused || false}
/>
@@ -74,7 +93,7 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
[...Object.values(props), tooltip],
);
const cellElement = useGridReactiveValue(cellContext?.cellElement, props.rowIdx, props.column.idx, mappedProps, renderDefaultCell);
const cellElement = useGridReactiveValue(cellContext?.cellElement, rowIdx, dataColIdx, mappedProps, renderDefaultCell);
const innerCellContext = useMemo<IDataGridCellInnerContext>(() => ({ isFocused: props.isCellSelected }), [props.isCellSelected]);
return <DataGridCellInnerContext value={innerCellContext}>{cellElement ?? <Cell title={tooltip} {...props} />}</DataGridCellInnerContext>;
@@ -8,6 +8,10 @@
}
@layer components.rdg.Cell {
.rdg {
--dbv-kit-icon-btn-outline-width: 1px;
}
@media (prefers-color-scheme: dark) {
.rdg-cell-frozen {
&:nth-last-child(1 of &) {
@@ -1,5 +1,5 @@
import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle } from 'react-data-grid';
import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle, type ColumnWidth, type ColumnWidths } from 'react-data-grid';
import { rowRenderer } from './renderers/rowRenderer.js';
import { cellRenderer } from './renderers/cellRenderer.js';
import { DataGridCellHeaderContext, type IDataGridHeaderCellContext } from './DataGridHeaderCellContext.js';
@@ -12,6 +12,7 @@ import { mapRenderHeaderCell } from './mapRenderHeaderCell.js';
import { mapEditCellRenderer } from './mapEditCellRenderer.js';
import { DataGridRowContext, type IDataGridRowContext } from './DataGridRowContext.js';
import './DataGrid.css';
import { HeaderDnDContext, useHeaderDnD } from './useHeaderDnD.js';
export interface ICellPosition {
rowIdx: number;
@@ -46,9 +47,13 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
headerElement,
getHeaderWidth,
headerText,
getHeaderOrder,
getHeaderResizable,
columnSortable,
getHeaderHeight,
getHeaderPinned,
columnSortingState,
getHeaderDnD,
cell,
cellText,
cellElement,
@@ -59,20 +64,23 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
rowCount,
getRowId,
getRowHeight,
onHeaderReorder,
onScroll,
onScrollToBottom,
onFocus,
onCellChange,
onColumnSort,
onHeaderKeyDown,
children,
className,
onCellKeyDown,
},
ref,
) {
const [columnWidths, setColumnWidths] = useState<ColumnWidths>(() => new Map<string, ColumnWidth>());
const rowsCount = useGridReactiveValue(rowCount);
const columnsCount = useGridReactiveValue(columnCount);
const gridKey = useRef(0);
const rowsCountRef = useRef(rowsCount);
const innerGridRef = useRef<DataGridHandle>(null);
const columns = new Array<ColumnOrColumnGroup<IInnerRow, unknown>>(columnsCount)
@@ -87,21 +95,25 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
minWidth: 26,
editable: row => getCellEditable?.(row.idx, i) ?? false,
frozen: getHeaderPinned?.(i),
renderHeaderCell: mapRenderHeaderCell,
renderCell: mapCellContentRenderer,
renderEditCell: mapEditCellRenderer,
renderHeaderCell: mapRenderHeaderCell(i),
renderCell: mapCellContentRenderer(i),
renderEditCell: mapEditCellRenderer(i),
};
});
const dndHeaderContext = useHeaderDnD({ columns, onReorder: onHeaderReorder, getCanDrag: getHeaderDnD, getHeaderOrder });
useImperativeHandle(ref, () => ({
selectCell: (position: ICellPosition) => {
innerGridRef.current?.selectCell({ idx: position.colIdx, rowIdx: position.rowIdx });
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx });
},
scrollToCell: (position: Partial<ICellPosition>) => {
innerGridRef.current?.scrollToCell({ idx: position.colIdx, rowIdx: position.rowIdx });
innerGridRef.current?.scrollToCell({ idx: position.colIdx && dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx });
},
openEditor: (position: ICellPosition) => {
innerGridRef.current?.selectCell({ idx: position.colIdx, rowIdx: position.rowIdx }, true);
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx }, {
enableEditor: true,
});
},
}));
@@ -110,12 +122,11 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
rowsCountRef.current = rowsCount;
if (previousRowCount === 0) {
// we trigger columns size recalculation when rows are added
gridKey.current++;
setColumnWidths(new Map<string, ColumnWidth>());
}
}
const rows = useMemo(
let rows = useMemo(
() =>
new Array<IInnerRow>(rowsCount).fill({ idx: 0 }).map((_, i) => ({
idx: i,
@@ -124,34 +135,47 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
);
function handleCellFocus(args: CellSelectArgs<IInnerRow, unknown>) {
onFocus?.({ colIdx: args.column.idx, rowIdx: args.rowIdx });
onFocus?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx });
}
function handleCellKeyDown(args: CellSelectArgs<IInnerRow, unknown>, event: DataGridCellKeyboardEvent) {
onCellKeyDown?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx }, event);
}
const isMeasurementRender = columnWidths.size === 0 && columnCount.get() > 0;
if (isMeasurementRender) {
rows = rows.slice(0, 100);
}
return (
<DataGridRowContext value={{ rowCount, onScrollToBottom }}>
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
<DataGridCellHeaderContext value={{ headerElement, headerText }}>
<DataGridBase
key={gridKey.current}
ref={innerGridRef}
columns={columns}
rows={rows}
className={className}
headerRowHeight={getHeaderHeight?.()}
onScroll={onScroll}
rowHeight={getRowHeight ? row => getRowHeight(row.idx) : undefined}
rowKeyGetter={getRowId ? row => getRowId(row.idx) : undefined}
onSelectedCellChange={handleCellFocus}
onCellKeyDown={onCellKeyDown ? (args, event) => onCellKeyDown({ rowIdx: args.rowIdx, colIdx: args.column.idx }, event) : undefined}
renderers={{
renderRow: rowRenderer,
renderCell: cellRenderer,
noRowsFallback: children,
}}
minimumRowsToRender={100}
/>
</DataGridCellHeaderContext>
</DataGridCellContext>
</DataGridRowContext>
<HeaderDnDContext value={dndHeaderContext}>
<DataGridRowContext value={{ rowCount, onScrollToBottom }}>
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
<DataGridCellHeaderContext value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState, onHeaderKeyDown }}>
<DataGridBase
ref={innerGridRef}
columns={dndHeaderContext.columns}
enableVirtualization={!isMeasurementRender}
rows={rows}
className={className}
headerRowHeight={getHeaderHeight?.()}
rowHeight={getRowHeight ? row => getRowHeight(row.idx) : undefined}
rowKeyGetter={getRowId ? row => getRowId(row.idx) : undefined}
columnWidths={columnWidths}
renderers={{
renderRow: rowRenderer,
renderCell: cellRenderer,
noRowsFallback: children,
}}
onScroll={onScroll}
onSelectedCellChange={handleCellFocus}
onCellKeyDown={handleCellKeyDown}
onColumnWidthsChange={setColumnWidths}
/>
</DataGridCellHeaderContext>
</DataGridCellContext>
</DataGridRowContext>
</HeaderDnDContext>
);
});
@@ -4,10 +4,17 @@ import type { IGridReactiveValue } from './IGridReactiveValue.js';
export interface IDataGridHeaderCellContext {
headerElement?: IGridReactiveValue<React.ReactNode, [colIdx: number]>;
headerText?: IGridReactiveValue<string, [colIdx: number]>;
getHeaderOrder?: () => number[];
getHeaderWidth?: (colIdx: number) => number | string | null;
getHeaderResizable?: (colIdx: number) => boolean;
getHeaderHeight?: () => number;
getHeaderPinned?: (colIdx: number) => boolean;
getHeaderDnD?: (colIdx: number) => boolean;
onHeaderReorder?: (from: number, to: number) => void;
columnSortingState?: IGridReactiveValue<'asc' | 'desc' | undefined | null, [colIdx: number]>;
columnSortable?: IGridReactiveValue<boolean, [colIdx: number]>;
onColumnSort?: (colIdx: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
onHeaderKeyDown?: (event: React.KeyboardEvent) => void;
}
export const DataGridCellHeaderContext = createContext<IDataGridHeaderCellContext | null>(null);
@@ -4,11 +4,12 @@ import { Checkbox, clsx, Focusable } from '@dbeaver/ui-kit';
interface Props {
value: boolean | null;
className?: string;
focusable?: boolean;
onClick?: React.MouseEventHandler<HTMLElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
}
export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props) {
export function BooleanFormatter({ value, className, onClick, onKeyDown, focusable }: Props) {
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.code === 'Enter' || event.code === 'Space') {
event.preventDefault();
@@ -17,11 +18,12 @@ export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props
};
return (
<Focusable
focusable={focusable}
className={clsx('tw:flex tw:items-center tw:outline-none tw:hover:cursor-pointer', className)}
onKeyDown={handleKeyDown}
onClick={onClick}
>
{value === null ? <NullFormatter /> : <Checkbox className="tw:data-disabled:opacity-100" disabled size="small" checked={value} />}
{value === null ? <NullFormatter /> : <Checkbox className="tw:data-disabled:opacity-100!" disabled size="small" checked={value} />}
</Focusable>
);
}
@@ -4,6 +4,7 @@ export * from './DataGridCellInnerContext.js';
export * from './IGridReactiveValue.js';
export * from './useCreateGridReactiveValue.js';
export * from './useGridReactiveValue.js';
export * from './reorderArray.js';
export * from './formatters/NullFormatter.js';
export * from './formatters/BooleanFormatter.js';
@@ -2,6 +2,8 @@ import type { RenderCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { CellContentRenderer } from './renderers/CellContentRenderer.js';
export function mapCellContentRenderer({ rowIdx, column }: RenderCellProps<IInnerRow, unknown>) {
return <CellContentRenderer rowIdx={rowIdx} colIdx={column.idx} />;
export function mapCellContentRenderer(colIdx: number) {
return function RenderCell({ rowIdx }: RenderCellProps<IInnerRow, unknown>) {
return <CellContentRenderer rowIdx={rowIdx} colIdx={colIdx} />;
};
}
@@ -2,6 +2,8 @@ import type { RenderEditCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { TextEditor } from './editors/TextEditor.js';
export function mapEditCellRenderer({ rowIdx, column, onClose }: RenderEditCellProps<IInnerRow, unknown>) {
return <TextEditor rowIdx={rowIdx} colIdx={column.idx} onClose={() => onClose()} />;
export function mapEditCellRenderer(colIdx: number) {
return function RenderEditCell({ rowIdx, onClose }: RenderEditCellProps<IInnerRow, unknown>) {
return <TextEditor rowIdx={rowIdx} colIdx={colIdx} onClose={() => onClose()} />;
};
}
@@ -2,6 +2,8 @@ import type { RenderHeaderCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { HeaderCellContentRenderer } from './renderers/HeaderCellContentRenderer.js';
export function mapRenderHeaderCell({ column }: RenderHeaderCellProps<IInnerRow, unknown>) {
return <HeaderCellContentRenderer colIdx={column.idx} />;
export function mapRenderHeaderCell(colIdx: number) {
return function RenderHeaderCell({ tabIndex }: RenderHeaderCellProps<IInnerRow, unknown>) {
return <HeaderCellContentRenderer colIdx={colIdx} tabIndex={tabIndex} />;
};
}
@@ -1,13 +1,85 @@
import { use } from 'react';
import { memo, use } from 'react';
import { useDrag, useDrop, type DnDStoreProvider } from '@dbeaver/react-dnd';
import { DataGridCellHeaderContext } from '../DataGridHeaderCellContext.js';
import { useGridReactiveValue } from '../useGridReactiveValue.js';
import { HeaderDnDContext } from '../useHeaderDnD.js';
import { OrderButton } from './OrderButton.js';
interface Props {
colIdx: number;
tabIndex?: number;
}
export function HeaderCellContentRenderer({ colIdx }: Props) {
export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer({ colIdx, tabIndex }: Props) {
const dndHeaderContext = use(HeaderDnDContext);
const cellHeaderContext = use(DataGridCellHeaderContext);
const headerElement = useGridReactiveValue(cellHeaderContext?.headerElement, colIdx);
const getHeaderText = useGridReactiveValue(headerElement ? undefined : cellHeaderContext?.headerText, colIdx);
return headerElement ?? getHeaderText ?? '';
}
const isColumnSortable = useGridReactiveValue(cellHeaderContext?.columnSortable, colIdx);
const onColumnSort = cellHeaderContext?.onColumnSort;
const onHeaderKeyDown = cellHeaderContext?.onHeaderKeyDown;
const sortingState = useGridReactiveValue(cellHeaderContext?.columnSortingState, colIdx);
const draggable = dndHeaderContext?.getCanDrag?.(colIdx) ?? false;
const drag = useDrag({
draggable,
onDragStart(event, store) {
if (dndHeaderContext?.id) {
store.setData('dbeaver-react-data-grid-id', dndHeaderContext?.id);
}
store.setData('dbeaver-react-data-grid-col-idx', colIdx);
},
onDragEnd() {
dndHeaderContext?.onDragEnd(colIdx);
},
});
function canDrop(event: React.DragEvent<HTMLElement>, store: DnDStoreProvider | null) {
const gridId = store?.getData('dbeaver-react-data-grid-id');
return gridId === dndHeaderContext?.id;
}
const drop = useDrop({
canDrop,
onDragOver(event, store) {
if (!canDrop(event, store)) {
return;
}
const dragColIdx = store?.getData('dbeaver-react-data-grid-col-idx');
const position = event.clientX - event.currentTarget.getBoundingClientRect().left;
const width = event.currentTarget.offsetWidth;
const isAfter = position > width / 2;
dndHeaderContext?.onDragOver(dragColIdx, colIdx, isAfter);
},
});
function handleSort(e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) {
if (!onColumnSort) return;
const nextSortState = sortingState === 'asc' ? 'desc' : sortingState === 'desc' ? null : 'asc';
onColumnSort(colIdx, nextSortState, e.ctrlKey || e.metaKey);
}
function onKeyDown(event: React.KeyboardEvent<HTMLElement>) {
onHeaderKeyDown?.(event);
if ((event.key === 'Enter' || event.key === ' ') && isColumnSortable && onColumnSort) {
event.preventDefault();
handleSort(event);
}
}
return (
<div
onKeyDown={onKeyDown}
tabIndex={tabIndex}
className="tw:w-full tw:h-full tw:content-center tw:flex tw:items-center tw:justify-between tw:gap-1 tw:outline-none tw:group"
{...drag.props}
{...drop.props}
>
<span className="tw:overflow-hidden tw:h-full tw:text-ellipsis">{headerElement ?? getHeaderText ?? ''}</span>
{isColumnSortable && onColumnSort && <OrderButton sortState={sortingState} onClick={handleSort} />}
</div>
);
});
@@ -0,0 +1,32 @@
import { clsx, IconButton, Icon } from '@dbeaver/ui-kit';
interface OrderButtonProps {
sortState?: 'asc' | 'desc' | null;
onClick: (e: React.MouseEvent<HTMLElement>) => void;
tabIndex?: number;
}
export function OrderButton({ sortState, onClick, tabIndex }: OrderButtonProps) {
const svgSortAsc = 'sort-asc';
const svgSortDesc = 'sort-desc';
const svgSortUnknown = 'sort-unknown';
const iconSrc = sortState === 'asc' ? svgSortAsc : sortState === 'desc' ? svgSortDesc : svgSortUnknown;
return (
<IconButton
variant="secondary"
size="small"
onClick={onClick}
tabIndex={tabIndex}
title="Sort by column"
aria-label="Sort by column"
className={clsx(
'tw:opacity-0 tw:group-focus:opacity-100 tw:focus:opacity-100 tw:group-hover:opacity-100 tw:hover:opacity-100 tw:outline-offset-0',
sortState && 'tw:opacity-100',
)}
>
<Icon name={iconSrc} />
</IconButton>
);
}
@@ -0,0 +1,11 @@
export function reorderArray<T>(array: T[], from: number, to: number): T[] {
const newArray = [...array];
if (from < to) {
newArray.splice(to, 0, array[from]!);
newArray.splice(from, 1);
} else {
newArray.splice(from, 1);
newArray.splice(to, 0, array[from]!);
}
return newArray;
}
@@ -0,0 +1,94 @@
import type { ColumnOrColumnGroup } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { createContext, useId, useMemo, useState } from 'react';
import { reorderArray } from './reorderArray.js';
interface IHeaderDnDOptions {
columns: Array<ColumnOrColumnGroup<IInnerRow, unknown>>;
getCanDrag?: (colIdx: number) => boolean;
onReorder?: (from: number, to: number) => void;
getHeaderOrder?: () => number[];
}
interface IHeaderDnD {
id: string;
columns: Array<ColumnOrColumnGroup<IInnerRow, unknown>>;
getDataColIdx: (virtualColIdx: number) => number;
getVirtualColIdx: (dataColIdx: number) => number;
getCanDrag?: (colIdx: number) => boolean;
onDragOver: (dragColIdx: number, dropColIdx: number, isAfter: boolean) => void;
onDragEnd: (colIdx: number) => void;
}
export const HeaderDnDContext = createContext<IHeaderDnD | null>(null);
export function useHeaderDnD({ columns, getCanDrag, onReorder, getHeaderOrder }: IHeaderDnDOptions): IHeaderDnD {
const id = useId();
const [activeDnDElement, setActiveDnDElement] = useState<number | null>(null);
const [dragOverElement, setDragOverElement] = useState<[number, boolean] | null>(null);
function getDataColIdx(virtualColIdx: number) {
// Given a visible (ordered) column index, return the original data column index
const order = getHeaderOrder?.();
if (order) {
return order[virtualColIdx] ?? virtualColIdx;
}
return virtualColIdx;
}
function getVirtualColIdx(dataColIdx: number) {
// Given the original data column index, return its visible (ordered) index
const order = getHeaderOrder?.();
if (order) {
return order.indexOf(dataColIdx);
}
return dataColIdx;
}
function onDragEnd(dragColIdx: number) {
setActiveDnDElement(null);
setDragOverElement(null);
if (dragOverElement) {
const isAfter = dragOverElement?.[1];
let to = dragOverElement?.[0];
if (isAfter) {
to = getDataColIdx(getVirtualColIdx(to) + 1);
}
onReorder?.(dragColIdx, to);
}
}
function onDragOver(dragColIdx: number, dropColIdx: number, isAfter: boolean) {
setActiveDnDElement(dragColIdx);
if (dragColIdx !== dropColIdx) {
setDragOverElement([dropColIdx, isAfter]);
}
}
columns = useMemo(() => columns.map((col, idx) => columns[getDataColIdx(idx)]!), [columns, getHeaderOrder]);
if (activeDnDElement !== null && dragOverElement !== null) {
const from = getVirtualColIdx(activeDnDElement);
let to = getVirtualColIdx(dragOverElement[0]);
const isAfter = dragOverElement[1];
if (isAfter) {
to++;
}
columns = reorderArray(columns, from, to);
}
return {
id,
columns,
getDataColIdx,
getVirtualColIdx,
getCanDrag,
onDragOver,
onDragEnd,
};
}
@@ -14,6 +14,9 @@
"src"
],
"references": [
{
"path": "../react-dnd"
},
{
"path": "../ui-kit"
}
@@ -0,0 +1 @@
# @dbeaver/react-dnd
@@ -0,0 +1,36 @@
{
"name": "@dbeaver/react-dnd",
"type": "module",
"sideEffects": [],
"exports": {
".": "./lib/index.js",
"./*": "./lib/*.js"
},
"scripts": {
"clear": "rimraf lib"
},
"files": [
"package.json",
"LICENSE",
"README.md",
"CHANGELOG.md",
"lib",
"!lib/**/*.d.ts.map",
"!lib/**/*.test.js",
"!lib/**/*.test.d.ts",
"!lib/**/*.test.d.ts.map",
"!lib/**/*.test.js.map",
"!lib/tests",
"!.tsbuildinfo"
],
"packageManager": "yarn@4.9.2",
"devDependencies": {
"@dbeaver/tsconfig": "workspace:^",
"@types/react": "^19",
"rimraf": "^6",
"typescript": "^5"
},
"dependencies": {
"react": "^19"
}
}
@@ -0,0 +1,3 @@
export * from './useDrag.js';
export * from './useDrop.js';
export { type DnDStoreProvider } from './store.js';
@@ -0,0 +1,46 @@
export const DND_STORE_PREFIX = 'application/dbeaver-react-dnd-';
export interface DnDStoreProvider {
getData: (key: string) => any;
setData: (key: string, value: any) => void;
removeData: () => void;
}
class DnDStore {
private data: Map<string, Record<string, any>> = new Map();
setData(id: string, key: string, value: any) {
if (!this.data.has(id)) {
this.data.set(id, {});
}
this.data.get(id)![key] = value;
}
getData(id: string, key: string) {
return this.data.get(id)?.[key];
}
removeData(id: string) {
this.data.delete(id);
}
getProvider(id: string) {
return {
getData: (key: string) => this.getData(id, key),
setData: (key: string, value: any) => {
this.setData(id, key, value);
},
removeData: () => {
this.removeData(id);
},
};
}
}
export function getStoreProvider(event: React.DragEvent<HTMLElement>): DnDStoreProvider | null {
const id = event.dataTransfer.types.find(type => type.startsWith(DND_STORE_PREFIX))?.slice(DND_STORE_PREFIX.length);
return id ? globalDnDStore.getProvider(id) : null;
}
// TODO: do we want to use react context here?
// the main idea was to use native DataTransfer, but it's available only for drag start and drop events
// so we need to use a custom store
export const globalDnDStore = new DnDStore();
@@ -0,0 +1,67 @@
import { useId, useMemo, useRef, useState } from 'react';
import { DND_STORE_PREFIX, globalDnDStore, type DnDStoreProvider } from './store.js';
interface IDragOptions {
draggable?: boolean;
onDrag?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
onDragStart?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
onDragEnd?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
}
interface IDrag {
isDragging: boolean;
props: {
draggable?: boolean;
onDrag: (event: React.DragEvent<HTMLElement>) => void;
onDragStart: (event: React.DragEvent<HTMLElement>) => void;
onDragEnd: (event: React.DragEvent<HTMLElement>) => void;
};
}
export function useDrag({ draggable, onDragStart, onDrag, onDragEnd }: IDragOptions = {}): IDrag {
const id = useId();
const [dragging, setDragging] = useState(false);
const optionsRef = useRef<IDragOptions>({ draggable, onDragStart, onDrag, onDragEnd });
optionsRef.current = { draggable, onDragStart, onDrag, onDragEnd };
function handleDragStart(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
event.stopPropagation();
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData(`${DND_STORE_PREFIX}${id}`, id);
setDragging(true);
optionsRef.current.onDragStart?.(event, globalDnDStore.getProvider(id));
}
function handleDrag(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
optionsRef.current.onDrag?.(event, globalDnDStore.getProvider(id));
}
function handleDragEnd(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
setDragging(false);
optionsRef.current.onDragEnd?.(event, globalDnDStore.getProvider(id));
globalDnDStore.removeData(id);
}
return {
isDragging: dragging,
props: {
draggable,
...useMemo(
() => ({
onDrag: handleDrag,
onDragStart: handleDragStart,
onDragEnd: handleDragEnd,
}),
[],
),
},
};
}
@@ -0,0 +1,61 @@
import { useMemo, useRef } from 'react';
import { getStoreProvider, type DnDStoreProvider } from './store.js';
interface IDropOptions {
canDrop?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => boolean;
onDrop?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragOver?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragEnter?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragLeave?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
}
interface IDrop {
props: {
onDrop: (event: React.DragEvent<HTMLElement>) => void;
onDragOver: (event: React.DragEvent<HTMLElement>) => void;
onDragEnter: (event: React.DragEvent<HTMLElement>) => void;
onDragLeave: (event: React.DragEvent<HTMLElement>) => void;
};
}
export function useDrop({ canDrop, onDrop, onDragOver, onDragEnter, onDragLeave }: IDropOptions = {}): IDrop {
const optionsRef = useRef<IDropOptions>({ canDrop, onDrop, onDragOver, onDragEnter, onDragLeave });
optionsRef.current = { canDrop, onDrop, onDragOver, onDragEnter, onDragLeave };
function handleOver(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
const isDroppable = optionsRef.current.canDrop?.(event, provider);
if (isDroppable) {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
} else {
event.dataTransfer.dropEffect = 'none';
}
optionsRef.current.onDragOver?.(event, provider);
}
function handleEnter(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDragEnter?.(event, provider);
}
function handleLeave(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDragLeave?.(event, provider);
}
function handleDrop(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDrop?.(event, provider);
}
return {
props: useMemo(
() => ({
onDrop: handleDrop,
onDragOver: handleOver,
onDragEnter: handleEnter,
onDragLeave: handleLeave,
}),
[],
),
};
}
@@ -0,0 +1,16 @@
{
"extends": "@dbeaver/tsconfig/tsconfig.webview.json",
"compilerOptions": {
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"rootDirs": [
"src"
],
"outDir": "lib",
"incremental": true,
"composite": true
},
"include": [
"src"
]
}
@@ -1,2 +1,14 @@
import '../src/index.css';
import './global.css';
import Icons from '../assets/icons/icons.svg?react';
import type { GlobalProvider } from '@ladle/react';
export const Provider: GlobalProvider = ({ children }) => {
return (
<div>
<Icons style={{ display: 'none' }} />
{children}
</div>
);
};
@@ -1,4 +1,4 @@
@import 'tailwindcss' prefix(tw);
@import 'tailwindcss' layer(base) prefix(tw);
@layer theme {
main {
@@ -86,6 +86,7 @@
:root[data-theme='dark'] {
--dbv-kit-color-foreground: var(--tw-color-gray-200);
--dbv-kit-color-background: var(--tw-color-gray-900);
--dbv-kit-btn-loader-base-color: var(--tw-color-gray-900);
/* Primary Button */
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="15" y="2" width="2" height="26" />
<rect class="cls-1" x="13.21" y="23.28" width="14.14" height="2.02"
transform="translate(-11.23 21.46) rotate(-45)" />
<rect class="cls-1" x="10.7" y="17.21" width="2.02" height="14.14"
transform="translate(-13.74 15.4) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 540 B

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="11.17" y="2" width="1.67" height="18.33" />
<rect class="cls-1" x="9.68" y="16.4" width="11.78" height="1.68"
transform="translate(-7.63 16.06) rotate(-45)" />
<rect class="cls-1" x="7.59" y="11.35" width="1.68" height="11.79"
transform="translate(-9.72 11.01) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 546 B

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="7.5" y="1" width="1" height="13" />
<rect class="cls-1" x="6.61" y="11.35" width="7.07" height="1.01"
transform="translate(-5.41 10.64) rotate(-45)" />
<rect class="cls-1" x="5.35" y="8.32" width="1.01" height="7.07"
transform="translate(-6.67 7.61) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 535 B

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="15" y="4" width="2" height="26" />
<rect class="cls-1" x="4.64" y="6.7" width="14.14" height="2.02"
transform="translate(-2.02 10.54) rotate(-45)" />
<rect class="cls-1" x="19.28" y=".64" width="2.02" height="14.14"
transform="translate(.49 16.6) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 532 B

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="11.17" y="3.67" width="1.67" height="18.33" />
<rect class="cls-1" x="2.54" y="5.92" width="11.78" height="1.68"
transform="translate(-2.31 7.94) rotate(-45)" />
<rect class="cls-1" x="14.73" y=".87" width="1.68" height="11.79"
transform="translate(-.22 12.99) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 546 B

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="7.5" y="2" width="1" height="13" />
<rect class="cls-1" x="2.32" y="3.64" width="7.07" height="1.01"
transform="translate(-1.21 5.36) rotate(-45)" />
<rect class="cls-1" x="9.64" y=".61" width="1.01" height="7.07"
transform="translate(.04 8.39) rotate(-45)" />
</svg>

After

Width:  |  Height:  |  Size: 530 B

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M5.76,18.69l-2.07,6.28H1.02L7.84,5h3.08l6.82,19.97h-2.76l-2.13-6.28h-7.08ZM12.34,16.68l-1.99-5.75c-.44-1.3-.74-2.49-1.04-3.65h-.06c-.3,1.16-.59,2.4-1.01,3.62l-1.96,5.78h6.05Z" />
<path class="cls-1"
d="M30.77,21.31c0,1.22.06,2.41.21,3.37h-2.34l-.21-1.77h-.09c-.8,1.1-2.34,2.09-4.39,2.09-2.9,0-4.39-2-4.39-4.04,0-3.4,3.08-5.26,8.62-5.23v-.29c0-1.13-.33-3.25-3.26-3.22-1.36,0-2.76.38-3.76,1.05l-.59-1.71c1.19-.73,2.93-1.22,4.74-1.22,4.39,0,5.45,2.93,5.45,5.72v5.26ZM28.25,17.51c-2.84-.06-6.08.43-6.08,3.17,0,1.68,1.13,2.44,2.43,2.44,1.9,0,3.11-1.16,3.53-2.35.09-.29.12-.58.12-.81v-2.44Z" />
</svg>

After

Width:  |  Height:  |  Size: 856 B

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M4.48,14.37l-1.52,4.61h-1.96L6.01,4.31h2.26l5.01,14.67h-2.02l-1.57-4.61h-5.2ZM9.31,12.89l-1.46-4.22c-.33-.96-.54-1.83-.76-2.68h-.04c-.22.85-.44,1.76-.74,2.65l-1.44,4.24h4.44Z" />
<path class="cls-1"
d="M22.85,16.29c0,.9.04,1.77.15,2.47h-1.72l-.15-1.3h-.07c-.59.81-1.72,1.53-3.22,1.53-2.13,0-3.22-1.47-3.22-2.96,0-2.5,2.26-3.86,6.33-3.84v-.21c0-.83-.24-2.39-2.39-2.37-1,0-2.02.28-2.76.77l-.44-1.26c.87-.53,2.15-.9,3.48-.9,3.22,0,4,2.15,4,4.2v3.86ZM21,13.5c-2.09-.04-4.46.32-4.46,2.32,0,1.24.83,1.79,1.78,1.79,1.39,0,2.29-.85,2.59-1.73.07-.21.09-.43.09-.6v-1.79Z" />
</svg>

After

Width:  |  Height:  |  Size: 832 B

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M2.53,9.63l-1.11,3.36H0L3.64,2.32h1.65l3.64,10.67h-1.47l-1.14-3.36h-3.78ZM6.05,8.55l-1.06-3.07c-.24-.7-.4-1.33-.55-1.95h-.03c-.16.62-.32,1.28-.54,1.93l-1.04,3.09h3.23Z" />
<path class="cls-1"
d="M15.89,11.03c0,.65.03,1.29.11,1.8h-1.25l-.11-.95h-.05c-.43.59-1.25,1.12-2.34,1.12-1.55,0-2.34-1.07-2.34-2.16,0-1.81,1.65-2.81,4.61-2.79v-.15c0-.6-.17-1.74-1.74-1.72-.73,0-1.47.2-2.01.56l-.32-.91c.63-.39,1.57-.65,2.53-.65,2.34,0,2.91,1.57,2.91,3.06v2.81ZM14.54,9c-1.52-.03-3.24.23-3.24,1.69,0,.9.6,1.3,1.3,1.3,1.01,0,1.66-.62,1.88-1.26.05-.15.06-.31.06-.43v-1.3Z" />
</svg>

After

Width:  |  Height:  |  Size: 828 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="2 10 12 10 7 4 2 10" />
<rect x="6" y="6" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</svg>

After

Width:  |  Height:  |  Size: 353 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="2 8.14 9.14 8.14 5.57 3.86 2 8.14" />
<rect x="4.86" y="5.29" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</svg>

After

Width:  |  Height:  |  Size: 414 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="0 4 5 4 2.5 1 0 4" />
<rect x="2" y="4" width="1" height="11" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</svg>

After

Width:  |  Height:  |  Size: 346 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="12 22 2 22 7 28 12 22" />
<rect x="6" y="4" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</svg>

After

Width:  |  Height:  |  Size: 355 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="9.14 16.71 2 16.71 5.57 21 9.14 16.71" />
<rect x="4.86" y="3.86" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</svg>

After

Width:  |  Height:  |  Size: 418 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="5 12 0 12 2.5 15 5 12" />
<rect x="2" y="1" width="1" height="12" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</svg>

After

Width:  |  Height:  |  Size: 350 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="4 10 14 10 9 4 4 10" />
<rect x="8" y="6" width="2" height="22" />
<polygon points="28 22 18 22 23 28 28 22" />
<rect x="22" y="4" width="2" height="22" />
</svg>

After

Width:  |  Height:  |  Size: 307 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="3.4 8.29 10.55 8.29 6.98 4 3.4 8.29" />
<rect x="6.26" y="5.43" width="1.43" height="15.71" />
<polygon points="20.55 16.86 13.4 16.86 16.98 21.14 20.55 16.86" />
<rect x="16.26" y="4" width="1.43" height="15.71" />
</svg>

After

Width:  |  Height:  |  Size: 367 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="2 4 7 4 4.5 1 2 4" />
<rect x="4" y="4" width="1" height="11" />
<polygon points="14 12 9 12 11.5 15 14 12" />
<rect x="11" y="1" width="1" height="11" />
</svg>

After

Width:  |  Height:  |  Size: 306 B

@@ -0,0 +1,302 @@
<svg xmlns="http://www.w3.org/2000/svg">
<!-- SORTING ICONS -->
<symbol id="icon-sort-unknown" viewBox="0 0 32 32" fill="currentColor">
<polygon points="4 10 14 10 9 4 4 10" />
<rect x="8" y="6" width="2" height="22" />
<polygon points="28 22 18 22 23 28 28 22" />
<rect x="22" y="4" width="2" height="22" />
</symbol>
<symbol id="icon-sort-unknown_m" viewBox="0 0 24 24" fill="currentColor">
<polygon points="3.4 8.29 10.55 8.29 6.98 4 3.4 8.29" />
<rect x="6.26" y="5.43" width="1.43" height="15.71" />
<polygon points="20.55 16.86 13.4 16.86 16.98 21.14 20.55 16.86" />
<rect x="16.26" y="4" width="1.43" height="15.71" />
</symbol>
<symbol id="icon-sort-unknown_sm" viewBox="0 0 16 16" fill="currentColor">
<polygon points="2 4 7 4 4.5 1 2 4" />
<rect x="4" y="4" width="1" height="11" />
<polygon points="14 12 9 12 11.5 15 14 12" />
<rect x="11" y="1" width="1" height="11" />
</symbol>
<symbol id="icon-sort-desc" viewBox="0 0 32 32"
fill="currentColor">
<polygon points="12 22 2 22 7 28 12 22" />
<rect x="6" y="4" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</symbol>
<symbol id="icon-sort-desc_m" viewBox="0 0 24 24"
fill="currentColor">
<polygon points="9.14 16.71 2 16.71 5.57 21 9.14 16.71" />
<rect x="4.86" y="3.86" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</symbol>
<symbol id="icon-sort-desc_sm" viewBox="0 0 16 16"
fill="currentColor">
<polygon points="5 12 0 12 2.5 15 5 12" />
<rect x="2" y="1" width="1" height="12" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</symbol>
<symbol id="icon-sort-asc" viewBox="0 0 32 32" fill="currentColor">
<polygon points="2 10 12 10 7 4 2 10" />
<rect x="6" y="6" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</symbol>
<symbol id="icon-sort-asc_m" viewBox="0 0 24 24" fill="currentColor">
<polygon points="2 8.14 9.14 8.14 5.57 3.86 2 8.14" />
<rect x="4.86" y="5.29" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</symbol>
<symbol id="icon-sort-asc_sm" viewBox="0 0 16 16" fill="currentColor">
<polygon points="0 4 5 4 2.5 1 0 4" />
<rect x="2" y="4" width="1" height="11" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</symbol>
<!-- SORTING ICONS END -->
<!-- CROSS ICON (ONLY ONE SIZE)-->
<symbol id="icon-cross_m" viewBox="0 0 24 24">
<path xmlns="http://www.w3.org/2000/svg" fill="currentColor" fill-rule="evenodd"
clip-rule="evenodd"
d="M3.31579 3.31579C2.89474 3.73684 2.89474 4.42105 3.31579 4.84211L10.4737 12L3.31579 19.1579C2.89474 19.5789 2.89474 20.2632 3.31579 20.6842C3.73684 21.1053 4.42105 21.1053 4.84211 20.6842L12 13.5263L19.1579 20.6842C19.5789 21.1053 20.2632 21.1053 20.6842 20.6842C21.1053 20.2632 21.1053 19.5789 20.6842 19.1579L13.5263 12L20.6842 4.84211C21.1053 4.42105 21.1053 3.73684 20.6842 3.31579C20.2632 2.89474 19.5789 2.89474 19.1579 3.31579L12 10.4737L4.84211 3.31579C4.42105 2.89474 3.73684 2.89474 3.31579 3.31579Z" />
</symbol>
<!-- CROSS ICON END -->
<!-- REPLACE ICONS -->
<symbol id="icon-replace_sm" viewBox="0 0 16 16" fill="currentColor">
<path
d="M10.03,1h1.04v2.39h.02c.24-.42.68-.69,1.3-.69.95,0,1.61.79,1.61,1.93,0,1.36-.86,2.04-1.71,2.04-.55,0-.99-.21-1.28-.71h-.02l-.04.62h-.95c.02-.26.03-.64.03-.98V1ZM11.06,4.97c0,.07,0,.13.03.19.11.37.48.62.93.62.65,0,1.03-.45,1.03-1.12,0-.59-.35-1.09-1.02-1.09-.41,0-.81.25-.93.65-.02.07-.04.14-.04.22v.52Z" />
<path
d="M8.99,13.78c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.4-1.04,1.19,0,.88.51,1.13,1.02,1.13.39,0,.77-.08.97-.17v.8Z" />
<path d="M13,9v6H3v-6h10M14,8H2v8h12V8h0Z" />
<path
d="M5,5h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
<polygon points="4.5 6 3 4 6 4 4.5 6" />
</symbol>
<symbol id="icon-replace_m" viewBox="0 0 24 24" fill="currentColor">
<path
d="M15.62.88h1.64v3.75h.02c.38-.67,1.07-1.09,2.04-1.09,1.49,0,2.53,1.24,2.53,3.04,0,2.14-1.36,3.2-2.69,3.2-.86,0-1.56-.33-2.01-1.11h-.02l-.06.98h-1.49c.02-.41.05-1.01.05-1.54V.88ZM17.23,7.12c0,.1.01.21.04.3.18.58.75.98,1.46.98,1.03,0,1.62-.71,1.62-1.77,0-.92-.55-1.71-1.6-1.71-.65,0-1.27.4-1.47,1.03-.03.1-.06.22-.06.35v.82Z" />
<path
d="M13.98,19.4c-.28.14-.91.35-1.72.35-1.8,0-2.98-1.22-2.98-3.05s1.26-3.19,3.21-3.19c.64,0,1.21.16,1.51.32v1.29c-.27-.14-.91-.36-1.51-.36-.93,0-1.64.64-1.64,1.87,0,1.38.81,1.77,1.6,1.77.62,0,1.21-.13,1.52-.26v1.26Z" />
<path d="M20.29,11.88v9.43H4.57v-9.43h15.71M21.86,10.31H3v12.57h18.86v-12.57h0Z" />
<path
d="M7.71,7.17h-1.57v-2.34c0-2.18,1.77-3.95,3.95-3.95h3.91v1.57h-3.91c-1.31,0-2.37,1.07-2.37,2.37v2.34Z" />
<polygon points="6.93 8.74 4.57 5.6 9.29 5.6 6.93 8.74" />
</symbol>
<symbol id="icon-replace" viewBox="0 0 32 32" fill="currentColor">
<path
d="M20.06,2h2.09v4.78h.03c.49-.85,1.37-1.38,2.59-1.38,1.9,0,3.22,1.57,3.22,3.87,0,2.72-1.73,4.07-3.43,4.07-1.1,0-1.98-.42-2.56-1.41h-.03l-.08,1.24h-1.9c.03-.52.06-1.29.06-1.96V2ZM22.11,9.94c0,.13.01.27.06.39.22.74.95,1.24,1.85,1.24,1.3,0,2.06-.91,2.06-2.25,0-1.17-.7-2.17-2.03-2.17-.83,0-1.61.51-1.87,1.3-.04.13-.07.28-.07.45v1.04Z" />
<path
d="M17.97,25.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.81-2.09,2.38,0,1.76,1.03,2.25,2.04,2.25.79,0,1.54-.16,1.94-.33v1.6Z" />
<path d="M26,16v12H6v-12h20M28,14H4v16h24V14h0Z" />
<path
d="M10,10h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
<polygon points="9 12 6 8 12 8 9 12" />
</symbol>
<!-- REPLACE ICONS END -->
<!-- REPLACE ALL ICONS -->
<symbol id="icon-replace-all" viewBox="0 0 32 32" fill="currentColor">
<path
d="M13,24.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM11.59,23.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
<path
d="M22.05,8.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM20.64,7.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
<path
d="M23.06,1.07h1.83v4.33h.03c.43-.77,1.2-1.25,2.27-1.25,1.66,0,2.82,1.42,2.82,3.5,0,2.46-1.51,3.69-3,3.69-.96,0-1.73-.38-2.24-1.28h-.03l-.07,1.12h-1.66c.03-.47.06-1.17.06-1.78V1.07ZM24.85,8.26c0,.12.01.24.05.35.2.67.84,1.13,1.62,1.13,1.14,0,1.8-.82,1.8-2.03,0-1.06-.61-1.97-1.78-1.97-.72,0-1.41.46-1.63,1.18-.04.12-.06.25-.06.4v.94Z" />
<path
d="M20.97,26.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.77-2.09,2.34,0,1.76,1.03,2.29,2.04,2.29.79,0,1.54-.16,1.94-.33v1.6Z" />
<path d="M24,18v10H4v-10h20M26,16H2v14h24v-14h0Z" />
<polygon points="9 12 9 14 28 14 28 28 30 28 30 12 9 12" />
<g>
<path
d="M6,13h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
<polygon points="5 15 2 11 8 11 5 15" />
</g>
</symbol>
<symbol id="icon-replace-all_m" viewBox="0 0 24 24" fill="currentColor">
<path
d="M9.25,19.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM8.19,17.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
<path
d="M16.04,7.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM14.98,5.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
<path
d="M16.79,1.07h1.37v3.24h.02c.32-.58.9-.94,1.7-.94,1.25,0,2.12,1.07,2.12,2.63,0,1.85-1.13,2.76-2.25,2.76-.72,0-1.3-.29-1.68-.96h-.02l-.05.84h-1.25c.02-.35.04-.88.04-1.33V1.07ZM18.14,6.46c0,.09,0,.18.04.26.15.5.63.84,1.22.84.86,0,1.35-.61,1.35-1.53,0-.8-.46-1.48-1.34-1.48-.54,0-1.06.34-1.22.89-.03.09-.05.19-.05.3v.7Z" />
<path
d="M15.23,20.19c-.27.13-.87.33-1.64.33-1.72,0-2.84-1.17-2.84-2.91s1.2-3.04,3.07-3.04c.61,0,1.16.15,1.44.31v1.23c-.25-.13-.87-.34-1.44-.34-.89,0-1.57.58-1.57,1.76,0,1.32.77,1.72,1.53,1.72.59,0,1.16-.12,1.45-.25v1.2Z" />
<path d="M17.5,13.77v7.5H2.5v-7.5h15M19,12.27H1v10.5h18v-10.5h0Z" />
<polygon
points="6.25 9.27 6.25 10.77 20.5 10.77 20.5 21.27 22 21.27 22 9.27 6.25 9.27" />
<g>
<path
d="M4,10.02h-1.5v-2.23c0-2.08,1.69-3.77,3.77-3.77h3.73v1.5h-3.73c-1.25,0-2.27,1.02-2.27,2.27v2.23Z" />
<polygon points="3.25 11.52 1 8.52 5.5 8.52 3.25 11.52" />
</g>
</symbol>
<symbol id="icon-replace-all_sm" viewBox="0 0 16 16" fill="currentColor">
<path
d="M6.5,13.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM5.8,12.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
<path
d="M11.02,4.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM10.32,3.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
<path
d="M11.53.54h.91v2.16h.01c.21-.38.6-.63,1.13-.63.83,0,1.41.71,1.41,1.75,0,1.23-.76,1.84-1.5,1.84-.48,0-.87-.19-1.12-.64h-.01l-.03.56h-.83c.01-.23.03-.58.03-.89V.54ZM12.43,4.13c0,.06,0,.12.02.17.1.33.42.56.81.56.57,0,.9-.41.9-1.02,0-.53-.31-.98-.89-.98-.36,0-.71.23-.82.59-.02.06-.03.13-.03.2v.47Z" />
<path
d="M10.48,14.28c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.38-1.04,1.17,0,.88.51,1.15,1.02,1.15.39,0,.77-.08.97-.17v.8Z" />
<path d="M12,10v5H2v-5h10M13,9H1v7h12v-7h0Z" />
<polygon points="4.5 7 4.5 8 14 8 14 15 15 15 15 7 4.5 7" />
<g>
<path
d="M3,7h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
<polygon points="2.5 8 1 6 4 6 2.5 8" />
</g>
</symbol>
<!-- REPLACE ALL ICONS END -->
<!-- REGEX ICONS -->
<symbol id="icon-regex" viewBox="0 0 32 32" fill="currentColor">
<rect x="20.04" y="2" width="2" height="22" />
<rect x="20.04" y="2" width="2" height="22"
transform="translate(-.9 24.42) rotate(-59.21)" />
<rect x="10.04" y="12" width="22" height="2"
transform="translate(-3.69 13.25) rotate(-32.29)" />
<rect x="2.04" y="22" width="8" height="8" />
</symbol>
<symbol id="icon-regex_m" viewBox="0 0 24 24" fill="currentColor">
<rect x="14.46" y="2" width="1.38" height="15.14" />
<rect x="14.46" y="2" width="1.38" height="15.14"
transform="translate(-.83 17.68) rotate(-59.21)" />
<rect x="7.58" y="8.88" width="15.14" height="1.38"
transform="translate(-2.77 9.57) rotate(-32.29)" />
<rect x="2.08" y="16.5" width="5.5" height="5.5" />
</symbol>
<symbol id="icon-regex_sm" viewBox="0 0 16 16" fill="currentColor">
<rect x="10" y="1" width="1" height="11" />
<rect x="10" y="1" width="1" height="11"
transform="translate(-.46 12.19) rotate(-59.21)" />
<rect x="5" y="6" width="11" height="1"
transform="translate(-1.85 6.61) rotate(-32.29)" />
<rect x="1" y="11" width="4" height="4" />
</symbol>
<!-- REGEX ICONS END -->
<!-- MATCH WORD ICONS -->
<symbol id="icon-match-word" viewBox="0 0 32 32" fill="currentColor">
<path
d="M13.82,20.03c0,1.12.05,2.22.18,3.1h-2.01l-.18-1.63h-.08c-.69,1.02-2.01,1.92-3.76,1.92-2.49,0-3.76-1.84-3.76-3.71,0-3.13,2.64-4.84,7.4-4.81v-.27c0-1.04-.28-2.99-2.8-2.97-1.17,0-2.36.35-3.23.96l-.51-1.58c1.02-.67,2.52-1.12,4.07-1.12,3.76,0,4.68,2.7,4.68,5.26v4.84ZM11.66,16.53c-2.44-.05-5.21.4-5.21,2.91,0,1.55.97,2.24,2.08,2.24,1.63,0,2.67-1.07,3.02-2.16.08-.27.1-.53.1-.75v-2.24Z" />
<path
d="M17.11,5h2.44v7.28h-.75c.87-1.44,2.44-2.35,4.62-2.35,3.39,0,5.75,2.67,5.75,6.57,0,4.62-3.08,6.92-6.11,6.92-1.96,0-2.72-.72-3.76-2.4h-.3l.1,2.11h-2.1c.06-.88.11-2.19.11-3.34V5ZM19.38,17.94c0,.29.08.59.17.85.45,1.63,1.21,2.75,3,2.75,2.61,0,4.12-2,4.12-4.97,0-2.59-1.4-4.81-4.06-4.81-1.65,0-2.55,1.12-3.06,2.89-.08.29-.17.61-.17.99v2.3Z" />
<rect x="1" y="23" width="2" height="4" />
<rect x="29" y="23" width="2" height="4" />
<rect x="1.67" y="25" width="29.33" height="2" />
</symbol>
<symbol id="icon-match-word_m" viewBox="0 0 24 24" fill="currentColor">
<path
d="M10.41,14.93c0,.82.04,1.61.13,2.25h-1.47l-.13-1.18h-.06c-.5.74-1.47,1.4-2.76,1.4-1.83,0-2.76-1.34-2.76-2.7,0-2.27,1.94-3.52,5.43-3.5v-.19c0-.76-.2-2.18-2.05-2.16-.86,0-1.73.25-2.37.7l-.37-1.15c.75-.49,1.85-.82,2.98-.82,2.76,0,3.43,1.96,3.43,3.83v3.52ZM8.82,12.38c-1.79-.04-3.82.29-3.82,2.12,0,1.13.71,1.63,1.53,1.63,1.19,0,1.96-.78,2.22-1.57.06-.19.07-.39.07-.54v-1.63Z" />
<path
d="M12.82,4h1.79v5.29h-.55c.64-1.05,1.79-1.71,3.39-1.71,2.49,0,4.21,1.94,4.21,4.78,0,3.36-2.26,5.03-4.48,5.03-1.44,0-2-.52-2.76-1.75h-.22l.08,1.54h-1.54c.04-.64.08-1.59.08-2.43V4ZM14.49,13.41c0,.21.06.43.12.62.33,1.19.89,2,2.2,2,1.91,0,3.02-1.46,3.02-3.61,0-1.88-1.03-3.5-2.98-3.5-1.21,0-1.87.82-2.24,2.1-.06.21-.12.45-.12.72v1.67Z" />
<rect x="1" y="17" width="1.47" height="3" />
<rect x="21.54" y="17" width="1.47" height="3" />
<rect x="1.49" y="18.55" width="21.52" height="1.45" />
</symbol>
<symbol id="icon-match-word_sm" viewBox="0 0 16 16" fill="currentColor">
<path
d="M6.9,10.2c0,.61.03,1.21.1,1.69h-1.15l-.1-.89h-.04c-.39.55-1.15,1.05-2.16,1.05-1.43,0-2.16-1.01-2.16-2.03,0-1.71,1.52-2.64,4.24-2.62v-.15c0-.57-.16-1.63-1.6-1.62-.67,0-1.35.19-1.85.52l-.29-.86c.58-.36,1.44-.61,2.33-.61,2.16,0,2.68,1.47,2.68,2.87v2.64ZM5.66,8.29c-1.4-.03-2.99.22-2.99,1.59,0,.85.55,1.22,1.19,1.22.93,0,1.53-.58,1.73-1.18.04-.15.06-.29.06-.41v-1.22Z" />
<path
d="M8.73,2h1.27v3.97h-.39c.45-.79,1.27-1.28,2.4-1.28,1.76,0,2.99,1.46,2.99,3.58,0,2.52-1.6,3.77-3.18,3.77-1.02,0-1.42-.39-1.95-1.31h.13l-.23,1.15h-1.09c.03-.48.06-1.19.06-1.82V2ZM9.93,9.06c0,.16.01.32.06.47.23.89.64,1.5,1.58,1.5,1.35,0,2.14-1.09,2.14-2.71,0-1.41-.73-2.62-2.11-2.62-.86,0-1.33.61-1.59,1.57-.04.16-.07.33-.07.54v1.25Z" />
<rect y="12" width="1" height="2" />
<rect x="15" y="12.02" width="1" height="1.98" />
<rect y="13" width="16" height="1" />
</symbol>
<!-- MATCH WORD ICONS END -->
<!-- CASE ICONS -->
<symbol id="icon-case" viewBox="0 0 32 32" fill="currentColor">
<path
d="M5.76,18.69l-2.07,6.28H1.02L7.84,5h3.08l6.82,19.97h-2.76l-2.13-6.28h-7.08ZM12.34,16.68l-1.99-5.75c-.44-1.3-.74-2.49-1.04-3.65h-.06c-.3,1.16-.59,2.4-1.01,3.62l-1.96,5.78h6.05Z" />
<path
d="M30.77,21.31c0,1.22.06,2.41.21,3.37h-2.34l-.21-1.77h-.09c-.8,1.1-2.34,2.09-4.39,2.09-2.9,0-4.39-2-4.39-4.04,0-3.4,3.08-5.26,8.62-5.23v-.29c0-1.13-.33-3.25-3.26-3.22-1.36,0-2.76.38-3.76,1.05l-.59-1.71c1.19-.73,2.93-1.22,4.74-1.22,4.39,0,5.45,2.93,5.45,5.72v5.26ZM28.25,17.51c-2.84-.06-6.08.43-6.08,3.17,0,1.68,1.13,2.44,2.43,2.44,1.9,0,3.11-1.16,3.53-2.35.09-.29.12-.58.12-.81v-2.44Z" />
</symbol>
<symbol id="icon-case_m" viewBox="0 0 24 24" fill="currentColor">
<path
d="M4.48,14.37l-1.52,4.61h-1.96L6.01,4.31h2.26l5.01,14.67h-2.02l-1.57-4.61h-5.2ZM9.31,12.89l-1.46-4.22c-.33-.96-.54-1.83-.76-2.68h-.04c-.22.85-.44,1.76-.74,2.65l-1.44,4.24h4.44Z" />
<path
d="M22.85,16.29c0,.9.04,1.77.15,2.47h-1.72l-.15-1.3h-.07c-.59.81-1.72,1.53-3.22,1.53-2.13,0-3.22-1.47-3.22-2.96,0-2.5,2.26-3.86,6.33-3.84v-.21c0-.83-.24-2.39-2.39-2.37-1,0-2.02.28-2.76.77l-.44-1.26c.87-.53,2.15-.9,3.48-.9,3.22,0,4,2.15,4,4.2v3.86ZM21,13.5c-2.09-.04-4.46.32-4.46,2.32,0,1.24.83,1.79,1.78,1.79,1.39,0,2.29-.85,2.59-1.73.07-.21.09-.43.09-.6v-1.79Z" />
</symbol>
<symbol id="icon-case_sm" viewBox="0 0 16 16" fill="currentColor">
<path
d="M2.53,9.63l-1.11,3.36H0L3.64,2.32h1.65l3.64,10.67h-1.47l-1.14-3.36h-3.78ZM6.05,8.55l-1.06-3.07c-.24-.7-.4-1.33-.55-1.95h-.03c-.16.62-.32,1.28-.54,1.93l-1.04,3.09h3.23Z" />
<path
d="M15.89,11.03c0,.65.03,1.29.11,1.8h-1.25l-.11-.95h-.05c-.43.59-1.25,1.12-2.34,1.12-1.55,0-2.34-1.07-2.34-2.16,0-1.81,1.65-2.81,4.61-2.79v-.15c0-.6-.17-1.74-1.74-1.72-.73,0-1.47.2-2.01.56l-.32-.91c.63-.39,1.57-.65,2.53-.65,2.34,0,2.91,1.57,2.91,3.06v2.81ZM14.54,9c-1.52-.03-3.24.23-3.24,1.69,0,.9.6,1.3,1.3,1.3,1.01,0,1.66-.62,1.88-1.26.05-.15.06-.31.06-.43v-1.3Z" />
</symbol>
<!-- CASE ICONS END -->
<!-- ARROW ICONS-->
<symbol id="icon-arrow-up" viewBox="0 0 32 32" fill="currentColor">
<rect x="15" y="4" width="2" height="26" />
<rect x="4.64" y="6.7" width="14.14" height="2.02"
transform="translate(-2.02 10.54) rotate(-45)" />
<rect x="19.28" y=".64" width="2.02" height="14.14"
transform="translate(.49 16.6) rotate(-45)" />
</symbol>
<symbol id="icon-arrow-up_m" viewBox="0 0 24 24" fill="currentColor">
<rect x="11.17" y="3.67" width="1.67" height="18.33" />
<rect x="2.54" y="5.92" width="11.78" height="1.68"
transform="translate(-2.31 7.94) rotate(-45)" />
<rect x="14.73" y=".87" width="1.68" height="11.79"
transform="translate(-.22 12.99) rotate(-45)" />
</symbol>
<symbol id="icon-arrow-up_sm" viewBox="0 0 16 16" fill="currentColor">
<rect x="7.5" y="2" width="1" height="13" />
<rect x="2.32" y="3.64" width="7.07" height="1.01"
transform="translate(-1.21 5.36) rotate(-45)" />
<rect x="9.64" y=".61" width="1.01" height="7.07"
transform="translate(.04 8.39) rotate(-45)" />
</symbol>
<symbol id="icon-arrow-down" viewBox="0 0 32 32" fill="currentColor">
<rect x="15" y="2" width="2" height="26" />
<rect x="13.21" y="23.28" width="14.14" height="2.02"
transform="translate(-11.23 21.46) rotate(-45)" />
<rect x="10.7" y="17.21" width="2.02" height="14.14"
transform="translate(-13.74 15.4) rotate(-45)" />
</symbol>
<symbol id="icon-arrow-down_m" viewBox="0 0 24 24" fill="currentColor">
<rect x="11.17" y="2" width="1.67" height="18.33" />
<rect x="9.68" y="16.4" width="11.78" height="1.68"
transform="translate(-7.63 16.06) rotate(-45)" />
<rect x="7.59" y="11.35" width="1.68" height="11.79"
transform="translate(-9.72 11.01) rotate(-45)" />
</symbol>
<symbol id="icon-arrow-down_sm" viewBox="0 0 16 16" fill="currentColor">
<rect x="7.5" y="1" width="1" height="13" />
<rect x="6.61" y="11.35" width="7.07" height="1.01"
transform="translate(-5.41 10.64) rotate(-45)" />
<rect x="5.35" y="8.32" width="1.01" height="7.07"
transform="translate(-6.67 7.61) rotate(-45)" />
</symbol>
<!-- ARROW ICONS END -->
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M13.82,20.03c0,1.12.05,2.22.18,3.1h-2.01l-.18-1.63h-.08c-.69,1.02-2.01,1.92-3.76,1.92-2.49,0-3.76-1.84-3.76-3.71,0-3.13,2.64-4.84,7.4-4.81v-.27c0-1.04-.28-2.99-2.8-2.97-1.17,0-2.36.35-3.23.96l-.51-1.58c1.02-.67,2.52-1.12,4.07-1.12,3.76,0,4.68,2.7,4.68,5.26v4.84ZM11.66,16.53c-2.44-.05-5.21.4-5.21,2.91,0,1.55.97,2.24,2.08,2.24,1.63,0,2.67-1.07,3.02-2.16.08-.27.1-.53.1-.75v-2.24Z" />
<path class="cls-1"
d="M17.11,5h2.44v7.28h-.75c.87-1.44,2.44-2.35,4.62-2.35,3.39,0,5.75,2.67,5.75,6.57,0,4.62-3.08,6.92-6.11,6.92-1.96,0-2.72-.72-3.76-2.4h-.3l.1,2.11h-2.1c.06-.88.11-2.19.11-3.34V5ZM19.38,17.94c0,.29.08.59.17.85.45,1.63,1.21,2.75,3,2.75,2.61,0,4.12-2,4.12-4.97,0-2.59-1.4-4.81-4.06-4.81-1.65,0-2.55,1.12-3.06,2.89-.08.29-.17.61-.17.99v2.3Z" />
<rect class="cls-1" x="1" y="23" width="2" height="4" />
<rect class="cls-1" x="29" y="23" width="2" height="4" />
<rect class="cls-1" x="1.67" y="25" width="29.33" height="2" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M10.41,14.93c0,.82.04,1.61.13,2.25h-1.47l-.13-1.18h-.06c-.5.74-1.47,1.4-2.76,1.4-1.83,0-2.76-1.34-2.76-2.7,0-2.27,1.94-3.52,5.43-3.5v-.19c0-.76-.2-2.18-2.05-2.16-.86,0-1.73.25-2.37.7l-.37-1.15c.75-.49,1.85-.82,2.98-.82,2.76,0,3.43,1.96,3.43,3.83v3.52ZM8.82,12.38c-1.79-.04-3.82.29-3.82,2.12,0,1.13.71,1.63,1.53,1.63,1.19,0,1.96-.78,2.22-1.57.06-.19.07-.39.07-.54v-1.63Z" />
<path class="cls-1"
d="M12.82,4h1.79v5.29h-.55c.64-1.05,1.79-1.71,3.39-1.71,2.49,0,4.21,1.94,4.21,4.78,0,3.36-2.26,5.03-4.48,5.03-1.44,0-2-.52-2.76-1.75h-.22l.08,1.54h-1.54c.04-.64.08-1.59.08-2.43V4ZM14.49,13.41c0,.21.06.43.12.62.33,1.19.89,2,2.2,2,1.91,0,3.02-1.46,3.02-3.61,0-1.88-1.03-3.5-2.98-3.5-1.21,0-1.87.82-2.24,2.1-.06.21-.12.45-.12.72v1.67Z" />
<rect class="cls-1" x="1" y="17" width="1.47" height="3" />
<rect class="cls-1" x="21.54" y="17" width="1.47" height="3" />
<rect class="cls-1" x="1.49" y="18.55" width="21.52" height="1.45" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<g>
<path class="cls-1"
d="M6.9,10.2c0,.61.03,1.21.1,1.69h-1.15l-.1-.89h-.04c-.39.55-1.15,1.05-2.16,1.05-1.43,0-2.16-1.01-2.16-2.03,0-1.71,1.52-2.64,4.24-2.62v-.15c0-.57-.16-1.63-1.6-1.62-.67,0-1.35.19-1.85.52l-.29-.86c.58-.36,1.44-.61,2.33-.61,2.16,0,2.68,1.47,2.68,2.87v2.64ZM5.66,8.29c-1.4-.03-2.99.22-2.99,1.59,0,.85.55,1.22,1.19,1.22.93,0,1.53-.58,1.73-1.18.04-.15.06-.29.06-.41v-1.22Z" />
<path class="cls-1"
d="M8.73,2h1.27v3.97h-.39c.45-.79,1.27-1.28,2.4-1.28,1.76,0,2.99,1.46,2.99,3.58,0,2.52-1.6,3.77-3.18,3.77-1.02,0-1.42-.39-1.95-1.31h.13l-.23,1.15h-1.09c.03-.48.06-1.19.06-1.82V2ZM9.93,9.06c0,.16.01.32.06.47.23.89.64,1.5,1.58,1.5,1.35,0,2.14-1.09,2.14-2.71,0-1.41-.73-2.62-2.11-2.62-.86,0-1.33.61-1.59,1.57-.04.16-.07.33-.07.54v1.25Z" />
</g>
<rect class="cls-1" y="12" width="1" height="2" />
<rect class="cls-1" x="15" y="12.02" width="1" height="1.98" />
<rect class="cls-1" y="13" width="16" height="1" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="20.04" y="2" width="2" height="22" />
<rect class="cls-1" x="20.04" y="2" width="2" height="22"
transform="translate(-.9 24.42) rotate(-59.21)" />
<rect class="cls-1" x="10.04" y="12" width="22" height="2"
transform="translate(-3.69 13.25) rotate(-32.29)" />
<rect class="cls-1" x="2.04" y="22" width="8" height="8" />
</svg>

After

Width:  |  Height:  |  Size: 590 B

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="14.46" y="2" width="1.38" height="15.14" />
<rect class="cls-1" x="14.46" y="2" width="1.38" height="15.14"
transform="translate(-.83 17.68) rotate(-59.21)" />
<rect class="cls-1" x="7.58" y="8.88" width="15.14" height="1.38"
transform="translate(-2.77 9.57) rotate(-32.29)" />
<rect class="cls-1" x="2.08" y="16.5" width="5.5" height="5.5" />
</svg>

After

Width:  |  Height:  |  Size: 615 B

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<rect class="cls-1" x="10" y="1" width="1" height="11" />
<rect class="cls-1" x="10" y="1" width="1" height="11"
transform="translate(-.46 12.19) rotate(-59.21)" />
<rect class="cls-1" x="5" y="6" width="11" height="1"
transform="translate(-1.85 6.61) rotate(-32.29)" />
<rect class="cls-1" x="1" y="11" width="4" height="4" />
</svg>

After

Width:  |  Height:  |  Size: 576 B

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M13,24.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM11.59,23.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
<path class="cls-1"
d="M22.05,8.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM20.64,7.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
<path class="cls-1"
d="M23.06,1.07h1.83v4.33h.03c.43-.77,1.2-1.25,2.27-1.25,1.66,0,2.82,1.42,2.82,3.5,0,2.46-1.51,3.69-3,3.69-.96,0-1.73-.38-2.24-1.28h-.03l-.07,1.12h-1.66c.03-.47.06-1.17.06-1.78V1.07ZM24.85,8.26c0,.12.01.24.05.35.2.67.84,1.13,1.62,1.13,1.14,0,1.8-.82,1.8-2.03,0-1.06-.61-1.97-1.78-1.97-.72,0-1.41.46-1.63,1.18-.04.12-.06.25-.06.4v.94Z" />
<path class="cls-1"
d="M20.97,26.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.77-2.09,2.34,0,1.76,1.03,2.29,2.04,2.29.79,0,1.54-.16,1.94-.33v1.6Z" />
<path class="cls-1" d="M24,18v10H4v-10h20M26,16H2v14h24v-14h0Z" />
<polygon class="cls-1" points="9 12 9 14 28 14 28 28 30 28 30 12 9 12" />
<g>
<path class="cls-1"
d="M6,13h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
<polygon class="cls-1" points="5 15 2 11 8 11 5 15" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M9.25,19.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM8.19,17.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
<path class="cls-1"
d="M16.04,7.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM14.98,5.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
<path class="cls-1"
d="M16.79,1.07h1.37v3.24h.02c.32-.58.9-.94,1.7-.94,1.25,0,2.12,1.07,2.12,2.63,0,1.85-1.13,2.76-2.25,2.76-.72,0-1.3-.29-1.68-.96h-.02l-.05.84h-1.25c.02-.35.04-.88.04-1.33V1.07ZM18.14,6.46c0,.09,0,.18.04.26.15.5.63.84,1.22.84.86,0,1.35-.61,1.35-1.53,0-.8-.46-1.48-1.34-1.48-.54,0-1.06.34-1.22.89-.03.09-.05.19-.05.3v.7Z" />
<path class="cls-1"
d="M15.23,20.19c-.27.13-.87.33-1.64.33-1.72,0-2.84-1.17-2.84-2.91s1.2-3.04,3.07-3.04c.61,0,1.16.15,1.44.31v1.23c-.25-.13-.87-.34-1.44-.34-.89,0-1.57.58-1.57,1.76,0,1.32.77,1.72,1.53,1.72.59,0,1.16-.12,1.45-.25v1.2Z" />
<path class="cls-1" d="M17.5,13.77v7.5H2.5v-7.5h15M19,12.27H1v10.5h18v-10.5h0Z" />
<polygon class="cls-1"
points="6.25 9.27 6.25 10.77 20.5 10.77 20.5 21.27 22 21.27 22 9.27 6.25 9.27" />
<g>
<path class="cls-1"
d="M4,10.02h-1.5v-2.23c0-2.08,1.69-3.77,3.77-3.77h3.73v1.5h-3.73c-1.25,0-2.27,1.02-2.27,2.27v2.23Z" />
<polygon class="cls-1" points="3.25 11.52 1 8.52 5.5 8.52 3.25 11.52" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M6.5,13.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM5.8,12.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
<path class="cls-1"
d="M11.02,4.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM10.32,3.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
<path class="cls-1"
d="M11.53.54h.91v2.16h.01c.21-.38.6-.63,1.13-.63.83,0,1.41.71,1.41,1.75,0,1.23-.76,1.84-1.5,1.84-.48,0-.87-.19-1.12-.64h-.01l-.03.56h-.83c.01-.23.03-.58.03-.89V.54ZM12.43,4.13c0,.06,0,.12.02.17.1.33.42.56.81.56.57,0,.9-.41.9-1.02,0-.53-.31-.98-.89-.98-.36,0-.71.23-.82.59-.02.06-.03.13-.03.2v.47Z" />
<path class="cls-1"
d="M10.48,14.28c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.38-1.04,1.17,0,.88.51,1.15,1.02,1.15.39,0,.77-.08.97-.17v.8Z" />
<path class="cls-1" d="M12,10v5H2v-5h10M13,9H1v7h12v-7h0Z" />
<polygon class="cls-1" points="4.5 7 4.5 8 14 8 14 15 15 15 15 7 4.5 7" />
<g>
<path class="cls-1"
d="M3,7h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
<polygon class="cls-1" points="2.5 8 1 6 4 6 2.5 8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M20.06,2h2.09v4.78h.03c.49-.85,1.37-1.38,2.59-1.38,1.9,0,3.22,1.57,3.22,3.87,0,2.72-1.73,4.07-3.43,4.07-1.1,0-1.98-.42-2.56-1.41h-.03l-.08,1.24h-1.9c.03-.52.06-1.29.06-1.96V2ZM22.11,9.94c0,.13.01.27.06.39.22.74.95,1.24,1.85,1.24,1.3,0,2.06-.91,2.06-2.25,0-1.17-.7-2.17-2.03-2.17-.83,0-1.61.51-1.87,1.3-.04.13-.07.28-.07.45v1.04Z" />
<path class="cls-1"
d="M17.97,25.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.81-2.09,2.38,0,1.76,1.03,2.25,2.04,2.25.79,0,1.54-.16,1.94-.33v1.6Z" />
<path class="cls-1" d="M26,16v12H6v-12h20M28,14H4v16h24V14h0Z" />
<path class="cls-1"
d="M10,10h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
<polygon class="cls-1" points="9 12 6 8 12 8 9 12" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M15.62.88h1.64v3.75h.02c.38-.67,1.07-1.09,2.04-1.09,1.49,0,2.53,1.24,2.53,3.04,0,2.14-1.36,3.2-2.69,3.2-.86,0-1.56-.33-2.01-1.11h-.02l-.06.98h-1.49c.02-.41.05-1.01.05-1.54V.88ZM17.23,7.12c0,.1.01.21.04.3.18.58.75.98,1.46.98,1.03,0,1.62-.71,1.62-1.77,0-.92-.55-1.71-1.6-1.71-.65,0-1.27.4-1.47,1.03-.03.1-.06.22-.06.35v.82Z" />
<path class="cls-1"
d="M13.98,19.4c-.28.14-.91.35-1.72.35-1.8,0-2.98-1.22-2.98-3.05s1.26-3.19,3.21-3.19c.64,0,1.21.16,1.51.32v1.29c-.27-.14-.91-.36-1.51-.36-.93,0-1.64.64-1.64,1.87,0,1.38.81,1.77,1.6,1.77.62,0,1.21-.13,1.52-.26v1.26Z" />
<path class="cls-1" d="M20.29,11.88v9.43H4.57v-9.43h15.71M21.86,10.31H3v12.57h18.86v-12.57h0Z" />
<path class="cls-1"
d="M7.71,7.17h-1.57v-2.34c0-2.18,1.77-3.95,3.95-3.95h3.91v1.57h-3.91c-1.31,0-2.37,1.07-2.37,2.37v2.34Z" />
<polygon class="cls-1" points="6.93 8.74 4.57 5.6 9.29 5.6 6.93 8.74" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<path class="cls-1"
d="M10.03,1h1.04v2.39h.02c.24-.42.68-.69,1.3-.69.95,0,1.61.79,1.61,1.93,0,1.36-.86,2.04-1.71,2.04-.55,0-.99-.21-1.28-.71h-.02l-.04.62h-.95c.02-.26.03-.64.03-.98V1ZM11.06,4.97c0,.07,0,.13.03.19.11.37.48.62.93.62.65,0,1.03-.45,1.03-1.12,0-.59-.35-1.09-1.02-1.09-.41,0-.81.25-.93.65-.02.07-.04.14-.04.22v.52Z" />
<path class="cls-1"
d="M8.99,13.78c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.4-1.04,1.19,0,.88.51,1.13,1.02,1.13.39,0,.77-.08.97-.17v.8Z" />
<path class="cls-1" d="M13,9v6H3v-6h10M14,8H2v8h12V8h0Z" />
<path class="cls-1"
d="M5,5h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
<polygon class="cls-1" points="4.5 6 3 4 6 4 4.5 6" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+7 -5
View File
@@ -7,26 +7,28 @@
"exports": {
".": "./lib/index.js",
"./*.css": "./src/*.css",
"./*": "./lib/*.js"
"./*": "./lib/*.js",
"./assets/icons/*.svg": "./assets/icons/*.svg"
},
"scripts": {
"build": "tsc -b",
"docs": "ladle serve",
"clean": "rimraf --glob lib"
},
"packageManager": "yarn@4.6.0",
"packageManager": "yarn@4.9.2",
"devDependencies": {
"@dbeaver/tsconfig": "workspace:^",
"@ladle/react": "^5",
"@tailwindcss/vite": "^4",
"@tailwindcss/vite": "4.0.7",
"@types/react": "^19",
"@types/react-dom": "^19",
"@wroud/vite-plugin-asset-resolver": "^0",
"@wroud/vite-plugin-tsc": "^0.11.6",
"rimraf": "^6",
"tailwindcss": "^4",
"tailwindcss": "4.0.7",
"typescript": "^5",
"vite": "^6"
"vite": "^7",
"vite-plugin-svgr": "^4.3.0"
},
"dependencies": {
"@ariakit/react": "^0",
@@ -0,0 +1,16 @@
export default function template(files) {
const exportLines = files.map((file) => {
const { path } = file;
const fileName = path.split('/').pop();
const componentNameWithExt = fileName.replace(/\.tsx$/, '.js');
const componentName = fileName.replace(/\.tsx$/, '');
return `export { default as ${componentName} } from './${componentNameWithExt}';`;
});
const header = '/* This file is automatically generated by the build:icons script. Do not modify it manually.*/\n\n ';
return header + exportLines.join('\n');
};
@@ -4,19 +4,8 @@
@layer base {
.dbv-kit-button {
display: inline-flex;
text-align: center;
text-decoration: none;
cursor: pointer;
user-select: none;
position: relative;
justify-content: center;
align-items: center;
white-space: nowrap;
height: var(--dbv-kit-btn-height);
padding-inline: var(--dbv-kit-btn-padding-inline);
gap: var(--dbv-kit-btn-gap);
background-color: var(--dbv-kit-btn-background);
color: var(--dbv-kit-btn-foreground);
@@ -29,6 +18,8 @@
font-size: var(--dbv-kit-btn-font-size);
font-weight: var(--dbv-kit-btn-font-weight);
cursor: pointer;
&:focus-visible,
&[data-focus-visible] {
outline: var(--dbv-kit-control-outline-width) solid var(--dbv-kit-btn-outline-color);
@@ -37,18 +28,16 @@
&:hover {
@media (hover: hover) {
color: var(--dbv-kit-btn-foreground-hover);
background-color: var(--dbv-kit-btn-background-hover);
}
}
&:active,
&[data-active] {
color: var(--dbv-kit-btn-foreground-active);
background-color: var(--dbv-kit-btn-background-active);
}
&:disabled {
opacity: var(--dbv-kit-control-disabled-opacity);
}
}
/* ---------------------------- */
@@ -94,72 +83,76 @@
/* Variants */
.dbv-kit-button--primary {
--dbv-kit-btn-background: var(--dbv-kit-btn-primary-background);
--dbv-kit-btn-foreground: var(--dbv-kit-btn-primary-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-primary-foreground-hover);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-primary-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-primary-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-primary-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-primary-background-active);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-background-hover);
--dbv-kit-btn-loader-background: var(--dbv-kit-btn-loader-base-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-primary-foreground);
&:disabled {
background-color: var(--dbv-kit-control-disabled-background);
color: var(--dbv-kit-control-disabled-foreground);
}
}
.dbv-kit-button--secondary {
--dbv-kit-btn-background: var(--dbv-kit-btn-secondary-background);
--dbv-kit-btn-foreground: var(--dbv-kit-btn-secondary-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-secondary-foreground-hover);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-secondary-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-secondary-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-secondary-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-secondary-background-active);
--dbv-kit-btn-border-color: var(--dbv-kit-btn-secondary-border-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-secondary-foreground);
--dbv-kit-btn-loader-background: var(--dbv-kit-btn-secondary-background-active);
&:disabled {
color: var(--dbv-kit-control-disabled-foreground);
border-color: var(--dbv-kit-control-disabled-foreground);
}
}
.dbv-kit-button--danger {
--dbv-kit-btn-background: var(--dbv-kit-btn-danger-background);
--dbv-kit-btn-foreground: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-danger-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-danger-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-danger-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-danger-background-active);
--dbv-kit-btn-border-color: var(--dbv-kit-btn-danger-border-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-danger-background);
--dbv-kit-btn-loader-background: var(--dbv-kit-btn-loader-base-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-outline-color: var(--dbv-kit-btn-danger-color-outline);
&:disabled {
background-color: var(--dbv-kit-control-disabled-background);
color: var(--dbv-kit-control-disabled-foreground);
}
}
/* ---------------------------- */
/* Loader */
.dbv-kit-button[data-loading='true'] {
opacity: 0.75;
color: color-mix(in oklch, var(--dbv-kit-btn-foreground) 25%, var(--dbv-kit-btn-loader-base-color));
background-color: color-mix(in oklch, var(--dbv-kit-btn-loader-base-color) 75%, var(--dbv-kit-btn-background));
background-color: var(--dbv-kit-btn-background-hover);
&:hover,
&:active,
&[data-active] {
background-color: color-mix(in oklch, var(--dbv-kit-btn-loader-base-color) 85%, var(--dbv-kit-btn-background));
background-color: var(--dbv-kit-btn-background-active);
}
}
.dbv-kit-button__loader {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
&::after {
--loader-width: calc(var(--dbv-kit-btn-font-size) * 0.2);
content: '';
border: var(--loader-width) solid var(--dbv-kit-btn-loader-background);
border-top: var(--loader-width) solid var(--dbv-kit-btn-loader-color);
border-radius: 50%;
opacity: 1;
width: calc(var(--dbv-kit-btn-font-size) * 1.25);
height: calc(var(--dbv-kit-btn-font-size) * 1.25);
animation: var(--dbv-kit-btn-loader-animation);
}
.dbv-kit-button .dbv-kit-spinner {
--dbv-kit-spinner-stroke-color: var(--dbv-kit-btn-loader-color);
--dbv-kit-spinner-height: calc(var(--dbv-kit-btn-height) * 0.6);
--dbv-kit-spinner-stroke-width: 3px;
}
/* ---------------------------- */
@@ -5,33 +5,21 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { Button as AriaButton, type ButtonProps as AriaKitButtonProps } from '@ariakit/react';
import clsx from 'clsx';
import './Button.css';
import type { ControlSize } from '../types/controls.js';
import { componentProviderWrapper } from '../componentProviderWrapper.js';
import { ButtonRoot, type ButtonRootProps } from './ButtonRoot.js';
import './Button.css';
export interface ButtonProps extends Omit<AriaKitButtonProps, 'clickOnEnter' | 'clickOnSpace'> {
export interface ButtonProps extends ButtonRootProps {
variant?: 'primary' | 'secondary' | 'danger';
size?: ControlSize;
loading?: boolean;
loader?: React.ReactNode;
}
export function ButtonBase({ className, variant = 'primary', size = 'medium', loading, loader, children, onClick, ...props }: ButtonProps) {
export function ButtonBase({ className, variant = 'primary', size = 'medium', ...props }: ButtonProps) {
const classToApply = clsx('dbv-kit-button', `dbv-kit-button--${variant}`, `dbv-kit-button--${size}`, className);
if (loading) {
props['aria-busy'] = true;
props['data-loading'] = true;
}
return (
<AriaButton onClick={loading ? () => null : onClick} className={classToApply} {...props}>
{loading && (loader ? loader : <span className="dbv-kit-button__loader" />)}
{children}
</AriaButton>
);
return <ButtonRoot className={classToApply} {...props} />;
}
export interface ButtonIconProps extends React.HTMLAttributes<HTMLSpanElement> {
placement?: 'start' | 'end';
@@ -42,9 +30,10 @@ export interface ButtonIconProps extends React.HTMLAttributes<HTMLSpanElement> {
*
* @param props.placement This property is needed to adjust icon placement inside a button. The icon with placement="start" will cut the inline-start padding. placement="end" will affect the padding-inline-end accordingly. This property supports RTL and LTR, so you don't need to think about it.
*/
ButtonBase.Icon = function ButtonBaseIcon({ className, children, placement }: ButtonIconProps) {
export function ButtonBaseIcon({ className, children, placement }: ButtonIconProps) {
const classToApply = clsx('dbv-kit-button__icon', placement && `dbv-kit-button__icon--${placement}`, className);
return <span className={classToApply}>{children}</span>;
};
}
export const Button = componentProviderWrapper('Button', ButtonBase);
export const ButtonIcon = componentProviderWrapper('ButtonIcon', ButtonBaseIcon);
@@ -0,0 +1,25 @@
@layer base {
.dbv-kit-button__loader {
position: absolute;
display: flex;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify-content: center;
align-items: center;
}
.dbv-kit-button__content {
display: flex;
text-align: center;
text-decoration: none;
user-select: none;
position: relative;
justify-content: center;
align-items: center;
white-space: nowrap;
transition: opacity 0.2s ease-in-out;
gap: var(--dbv-kit-btn-gap);
}
}
@@ -0,0 +1,23 @@
import { Button as AriaButton, type ButtonProps as AriaKitButtonProps } from '@ariakit/react';
import { Spinner } from '../Spinner/Spinner.js';
import { clsx } from '../utils/clsx.js';
import './ButtonRoot.css';
export interface ButtonRootProps extends Omit<AriaKitButtonProps, 'clickOnEnter' | 'clickOnSpace'> {
loading?: boolean;
loader?: React.ReactNode;
}
export function ButtonRoot({ loading, loader, children, onClick, className, ...props }: ButtonRootProps) {
if (loading) {
props['aria-busy'] = true;
props['data-loading'] = true;
}
return (
<AriaButton onClick={loading ? () => null : onClick} className={clsx(className, 'tw:relative')} {...props}>
<div className={clsx('dbv-kit-button__content', loading && 'tw:opacity-0')}>{children}</div>
{loading && <div className="dbv-kit-button__loader">{loader ? loader : <Spinner />}</div>}
</AriaButton>
);
}
@@ -2,14 +2,18 @@
:root {
--dbv-kit-btn-height: var(--dbv-kit-control-height-medium);
--dbv-kit-btn-padding-inline: calc(var(--tw-spacing) * 2.5);
--dbv-kit-btn-gap: calc(var(--dbv-kit-btn-padding-inline) / 4);
--dbv-kit-btn-gap: calc(var(--dbv-kit-btn-padding-inline) / 2);
--dbv-kit-btn-outline-offset: var(--dbv-kit-control-outline-offset);
--dbv-kit-btn-outline-color: var(--dbv-kit-control-outline-color);
--dbv-kit-btn-foreground: var(--tw-color-white);
--dbv-kit-btn-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-foreground-active: var(--tw-color-white);
--dbv-kit-btn-background: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-background-hover: var(--dbv-kit-color-primary-700);
--dbv-kit-btn-background-active: var(--dbv-kit-color-primary-800);
--dbv-kit-btn-outline-color: var(--dbv-kit-control-outline-color);
--dbv-kit-btn-border-width: var(--dbv-kit-control-border-width);
--dbv-kit-btn-border-color: transparent;
@@ -19,7 +23,7 @@
--dbv-kit-btn-font-weight: var(--tw-font-weight-normal);
--dbv-kit-btn-font-size: calc(var(--dbv-kit-font-size-base) * 0.875);
--dbv-kit-btn-loader-base-color: var(--tw-color-white);
--dbv-kit-btn-loader-animation: var(--tw-animate-spin);
--dbv-kit-btn-loader-base-color: var(--dbv-kit-btn-foreground);
--dbv-kit-btn-loader-height: calc(var(--dbv-kit-btn-height) * 0.6);
}
}
@@ -2,22 +2,30 @@
:root {
/* Primary Button */
--dbv-kit-btn-primary-foreground: var(--tw-color-white);
--dbv-kit-btn-primary-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-primary-foreground-active: var(--tw-color-white);
--dbv-kit-btn-primary-background: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-primary-background-hover: var(--dbv-kit-color-primary-700);
--dbv-kit-btn-primary-background-active: var(--dbv-kit-color-primary-800);
/* Secondary Button */
--dbv-kit-btn-secondary-foreground: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-foreground-active: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-background: transparent;
--dbv-kit-btn-secondary-background-hover: var(--dbv-kit-color-primary-50);
--dbv-kit-btn-secondary-background-active: var(--dbv-kit-color-primary-100);
--dbv-kit-btn-secondary-border-color: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-border-color-hover: var(--dbv-kit-color-primary-600);
/* Danger Button */
--dbv-kit-btn-danger-foreground: var(--tw-color-white);
--dbv-kit-btn-danger-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-danger-foreground-active: var(--tw-color-white);
--dbv-kit-btn-danger-background: var(--tw-color-red-600);
--dbv-kit-btn-danger-background-hover: var(--tw-color-red-700);
--dbv-kit-btn-danger-background-active: var(--tw-color-red-800);
--dbv-kit-btn-danger-border-color: transparent;
--dbv-kit-btn-danger-color-outline: var(--tw-color-red-300);
}
}
@@ -54,8 +54,8 @@ export function CheckboxBase({ children, className, icon, indeterminate, indeter
>
{checked &&
(icon ?? (
<svg fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 16 16">
<polyline points="3,7 7,11 13,4" />
<svg stroke="currentColor" strokeWidth="2" viewBox="0 0 16 16">
<polyline fill="none" points="3,7 7,11 13,4" />
</svg>
))}
{indeterminate &&
@@ -1,5 +1,6 @@
import { createContext } from 'react';
import type { ButtonBase } from './Button/Button.js';
import type { ButtonBase, ButtonBaseIcon } from './Button/Button.js';
import type { IconButtonBase } from './IconButton/IconButton.js';
import type { CheckboxBase } from './Checkbox/Checkbox.js';
import type { Radio } from './Radio/Radio.js';
import type { InputBase } from './Input/Input.js';
@@ -9,6 +10,8 @@ import type { SelectField } from './Select/SelectField.js';
export interface IComponentProvider {
Button?: typeof ButtonBase;
ButtonIcon?: typeof ButtonBaseIcon;
IconButton?: typeof IconButtonBase;
Input?: typeof InputBase;
Checkbox?: typeof CheckboxBase;
Radio?: typeof Radio;
@@ -0,0 +1,32 @@
import clsx from 'clsx';
type IconNames =
| 'replace'
| 'replace-all'
| 'match-word'
| 'case'
| 'regex'
| 'sort-asc'
| 'sort-desc'
| 'cross'
| 'sort-unknown'
| 'arrow-up'
| 'arrow-down';
export interface IconProps {
name: IconNames;
className?: string;
size?: 'small' | 'medium' | 'large';
color?: string;
style?: React.CSSProperties;
}
export function Icon({ name, className, size = 'small', color, style }: IconProps) {
const sizeAffix = size === 'small' ? '_sm' : size === 'large' ? '' : '_m';
const w = size === 'small' ? 16 : size === 'large' ? 32 : 24;
return (
<svg width={w} height={w} viewBox={`0 0 ${w} ${w}`} className={clsx('dbv-kit-icon', className)} style={{ color, ...style }}>
<use href={`#icon-${name}${sizeAffix}`} />
</svg>
);
}
@@ -0,0 +1,110 @@
@import './_base.css';
@import './_sizes.css';
@import './_variants.css';
@layer base {
.dbv-kit-icon-button {
min-width: var(--dbv-kit-icon-btn-size);
width: var(--dbv-kit-icon-btn-size);
height: var(--dbv-kit-icon-btn-size);
font-size: calc(var(--dbv-kit-icon-btn-size) * 0.75);
border-radius: var(--dbv-kit-icon-btn-border-radius);
border-color: var(--dbv-kit-icon-btn-border-color);
border-width: var(--dbv-kit-icon-btn-border-width);
border-style: var(--dbv-kit-icon-btn-border-style);
color: var(--dbv-kit-icon-btn-foreground);
background-color: var(--dbv-kit-icon-btn-background);
cursor: pointer;
&:focus-visible,
&[data-focus-visible] {
outline: var(--dbv-kit-icon-btn-outline-width) solid var(--dbv-kit-icon-btn-outline-color);
outline-offset: var(--dbv-kit-icon-btn-outline-offset);
}
&:hover {
@media (hover: hover) {
color: var(--dbv-kit-icon-btn-foreground-hover);
background-color: var(--dbv-kit-icon-btn-background-hover);
}
}
&:active,
&[data-active] {
color: var(--dbv-kit-icon-btn-foreground-active);
background-color: var(--dbv-kit-icon-btn-background-active);
}
&:disabled {
opacity: var(--dbv-kit-control-disabled-opacity);
}
&[data-loading='true'] {
background-color: var(--dbv-kit-icon-btn-background);
&:hover,
&:active,
&[data-active] {
background-color: var(--dbv-kit-icon-btn-background-active);
}
}
.dbv-kit-spinner {
--dbv-kit-spinner-stroke-color: var(--dbv-kit-icon-btn-loader-color);
--dbv-kit-spinner-height: calc(var(--dbv-kit-icon-btn-size) * 0.8);
--dbv-kit-spinner-stroke-width: 3px;
}
}
/* Size variants */
.dbv-kit-icon-button--small {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-small-size);
}
.dbv-kit-icon-button--medium {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-medium-size);
}
.dbv-kit-icon-button--large {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-large-size);
}
.dbv-kit-icon-button--xlarge {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-xlarge-size);
}
/* Variant styles */
.dbv-kit-icon-button--primary {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-primary-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-primary-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-primary-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-primary-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-primary-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-primary-background-active);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-primary-foreground);
}
.dbv-kit-icon-button--secondary {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-secondary-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-secondary-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-secondary-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-secondary-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-secondary-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-secondary-background-active);
--dbv-kit-icon-btn-border-color: var(--dbv-kit-icon-btn-secondary-border-color);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-secondary-loader-color);
}
.dbv-kit-icon-button--danger {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-danger-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-danger-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-danger-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-danger-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-danger-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-danger-background-active);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-danger-loader-color);
}
}
@@ -0,0 +1,32 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { clsx } from 'clsx';
import { componentProviderWrapper } from '../componentProviderWrapper.js';
import { ButtonRoot, type ButtonRootProps } from '../Button/ButtonRoot.js';
import type { ControlSize } from '../types/controls.js';
import './IconButton.css';
export interface IconButtonProps extends ButtonRootProps {
'aria-label': string;
variant?: 'primary' | 'secondary' | 'danger';
size?: ControlSize;
}
export function IconButtonBase({ className, variant = 'primary', size = 'medium', children, ...props }: IconButtonProps) {
const classToApply = clsx('dbv-kit-icon-button', `dbv-kit-icon-button--${variant}`, `dbv-kit-icon-button--${size}`, className);
return (
<ButtonRoot className={classToApply} {...props}>
{children}
</ButtonRoot>
);
}
export const IconButton = componentProviderWrapper('IconButton', IconButtonBase);
@@ -0,0 +1,30 @@
@layer base {
:root {
/* Icon Button border variables */
--dbv-kit-icon-btn-border-radius: var(--dbv-kit-btn-border-radius);
--dbv-kit-icon-btn-border-width: var(--dbv-kit-btn-border-width);
--dbv-kit-icon-btn-border-style: var(--dbv-kit-btn-border-style);
--dbv-kit-icon-btn-border-color: var(--dbv-kit-btn-border-color);
/* Icon Button outline variables */
--dbv-kit-icon-btn-outline-width: var(--dbv-kit-control-outline-width);
--dbv-kit-icon-btn-outline-style: var(--dbv-kit-control-outline-style);
--dbv-kit-icon-btn-outline-color: var(--dbv-kit-control-outline-color);
--dbv-kit-icon-btn-outline-offset: var(--dbv-kit-control-outline-offset);
/* Default size */
--dbv-kit-icon-btn-size: var(--dbv-kit-control-height-medium);
/* Default colors */
--dbv-kit-icon-btn-foreground: var(--tw-color-gray-600);
--dbv-kit-icon-btn-foreground-hover: var(--tw-color-gray-600);
--dbv-kit-icon-btn-foreground-active: var(--tw-color-gray-700);
--dbv-kit-icon-btn-background: transparent;
--dbv-kit-icon-btn-background-hover: var(--tw-color-gray-100);
--dbv-kit-icon-btn-background-active: var(--tw-color-gray-200);
/* Loader color */
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-foreground-hover);
--dbv-kit-btn-loader-base-color: transparent;
}
}
@@ -0,0 +1,8 @@
@layer base {
:root {
--dbv-kit-icon-btn-small-size: var(--dbv-kit-control-height-small);
--dbv-kit-icon-btn-medium-size: var(--dbv-kit-control-height-medium);
--dbv-kit-icon-btn-large-size: var(--dbv-kit-control-height-large);
--dbv-kit-icon-btn-xlarge-size: var(--dbv-kit-control-height-xlarge);
}
}
@@ -0,0 +1,31 @@
@layer base {
:root {
/* Primary */
--dbv-kit-icon-btn-primary-foreground: var(--tw-color-gray-600);
--dbv-kit-icon-btn-primary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-icon-btn-primary-foreground-active: var(--dbv-kit-color-primary-700);
--dbv-kit-icon-btn-primary-background: transparent;
--dbv-kit-icon-btn-primary-background-hover: var(--tw-color-gray-100);
--dbv-kit-icon-btn-primary-background-active: var(--tw-color-gray-200);
--dbv-kit-icon-btn-primary-loader-color: var(--tw-color-gray-300);
/* Secondary */
--dbv-kit-icon-btn-secondary-foreground: var(--tw-color-gray-500);
--dbv-kit-icon-btn-secondary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-icon-btn-secondary-foreground-active: var(--dbv-kit-color-primary-700);
--dbv-kit-icon-btn-secondary-background: transparent;
--dbv-kit-icon-btn-secondary-background-hover: transparent;
--dbv-kit-icon-btn-secondary-background-active: transparent;
--dbv-kit-icon-btn-secondary-border-color: transparent;
--dbv-kit-icon-btn-secondary-loader-color: var(--tw-color-gray-300);
/* Danger */
--dbv-kit-icon-btn-danger-foreground: var(--tw-color-red-600);
--dbv-kit-icon-btn-danger-foreground-hover: var(--tw-color-red-700);
--dbv-kit-icon-btn-danger-foreground-active: var(--tw-color-red-800);
--dbv-kit-icon-btn-danger-background: transparent;
--dbv-kit-icon-btn-danger-background-hover: var(--tw-color-red-100);
--dbv-kit-icon-btn-danger-background-active: var(--tw-color-red-200);
--dbv-kit-icon-btn-danger-loader-color: var(--tw-color-red-300);
}
}
@@ -1,13 +1,11 @@
@layer base {
.dbv-kit-radio-group {
display: flex;
gap: calc(var(--dbv-kit-radio-gap) * 4);
&.dbv-kit-radio-group--vertical {
flex-direction: column;
}
&:not(.dbv-kit-radio-group--vertical) .dbv-kit-radio {
margin-inline-end: calc(var(--dbv-kit-radio-gap) * 4);
gap: 0;
}
}
@@ -48,7 +48,7 @@ export function RadioGroup({ className, children, labelledBy, label, ['aria-labe
</div>
)}
<_RadioGroup
aria-labelledby={labelledById}
aria-labelledby={ariaLabel ? undefined : labelledById}
aria-label={ariaLabel}
className={clsx('dbv-kit-radio-group', className, props.vertical && 'dbv-kit-radio-group--vertical')}
>
@@ -20,19 +20,20 @@
font-weight: var(--dbv-kit-select-font-weight);
font-size: var(--dbv-kit-select-font-size);
outline-width: var(--dbv-kit-control-outline-width);
outline-offset: var(--dbv-kit-control-outline-offset);
outline-color: var(--dbv-kit-control-outline-color);
&:hover {
border-color: var(--dbv-kit-color-control-hover);
&:hover:not(:disabled) {
border-color: var(--dbv-kit-select-hover-border-color);
}
&[aria-disabled='true'] {
opacity: var(--dbv-kit-control-disabled-opacity);
color: var(--dbv-kit-select-disabled-foreground);
background-color: var(--dbv-kit-select-disabled-background);
}
&[data-focus-visible],
&:focus-visible {
outline-style: solid;
outline-offset: var(--dbv-kit-control-outline-offset);
}
}
@@ -74,6 +75,8 @@
.dbv-kit-select__item {
display: block;
width: 100%;
font-weight: var(--dbv-kit-select-font-weight);
font-size: var(--dbv-kit-select-font-size);
padding-inline: var(--dbv-kit-select-item-padding-inline);
padding-block: var(--dbv-kit-select-item-padding-block);
text-align: left;
@@ -8,7 +8,7 @@
import { useState } from 'react';
import clsx from 'clsx';
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel } from './Select.js';
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel, type SelectProviderProps } from './Select.js';
import './SelectField.css';
export interface SelectItem<T> {
@@ -57,6 +57,8 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
className?: string;
noItemsPlaceholder?: React.ReactNode;
/**
* Custom renderer for the selected value, overrides itemRenderer for the selected state
* Only needed for special formatting of the selected value different from list items
@@ -67,6 +69,16 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
* Custom arrow icon React Node that will be rendered instead default one
*/
arrowIcon?: React.ReactNode;
store?: SelectProviderProps['store'];
autoFocusItemsOnShow?: boolean;
'aria-labelledby'?: string,
'aria-label'?: string
id?: string;
}
// Utility function to get value by it's key or using getter function
@@ -82,13 +94,17 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
itemRender,
itemDisabled,
label,
noItemsPlaceholder = 'No items',
description,
disabled,
required,
className,
selectedRender,
arrowIcon,
store,
autoFocusItemsOnShow,
name,
id,
}: SelectFieldProps<T, ItemType>) {
const getItemValue = (item: ItemType): T =>
getValueByPath<ItemType, T>(item, itemValue, i => ('value' in i ? (i as unknown as SelectItem<T>).value : (i as unknown as T)));
@@ -115,29 +131,28 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
const selectedItem = items.find(item => getItemValue(item) === currentValue);
const displayValue = selectedItem ? (selectedRender ? selectedRender(currentValue, selectedItem) : renderItem(selectedItem)) : '';
const displayValue = selectedRender ? selectedRender(currentValue, selectedItem) : selectedItem ? renderItem(selectedItem) : '';
return (
<div className={clsx('dbv-kit-select-field', className)}>
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)}>
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)} store={store}>
{label && <SelectLabel className={clsx(required && 'dbv-kit-select__label--required')}>{label}</SelectLabel>}
<Select name={name} disabled={disabled}>
<Select id={id} name={name} disabled={disabled} required={required}>
{displayValue}
{arrowIcon ?? <Select.Arrow />}
{arrowIcon ?? <Select.Arrow className='dbv-kit-select__arrow-icon' />}
</Select>
{description && <span className="dbv-kit-select__description">{description}</span>}
<SelectPopover gutter={4} unmountOnHide>
<SelectPopover autoFocusOnShow={autoFocusItemsOnShow} gutter={4} unmountOnHide>
{items.length === 0 ? (
<div className="dbv-kit-select__empty">No items</div>
<div className="dbv-kit-select__empty">{noItemsPlaceholder}</div>
) : (
items.map(item => (
<SelectItem
key={String(getItemValue(item))}
value={getItemValue(item) as any}
disabled={isItemDisabled(item)}
className="dbv-kit-select__item"
>
{renderItem(item)}
</SelectItem>
@@ -5,11 +5,14 @@
--dbv-kit-select-foreground: var(--dbv-kit-color-foreground);
--dbv-kit-select-background: var(--dbv-kit-color-background);
--dbv-kit-select-disabled-foreground: var(--dbv-kit-control-disabled-foreground);
--dbv-kit-select-disabled-background: var(--dbv-kit-control-disabled-background);
--dbv-kit-select-border-width: var(--dbv-kit-control-border-width);
--dbv-kit-select-border-color: var(--dbv-kit-color-control-inactive);
--dbv-kit-select-border-style: solid;
--dbv-kit-select-border-radius: var(--dbv-kit-control-border-radius);
--dbv-kit-select-hover-border-color: var(--dbv-kit-color-control-hover);
--dbv-kit-select-font-weight: var(--tw-font-weight-normal);
--dbv-kit-select-font-size: calc(var(--dbv-kit-font-size-base) * 0.875);
@@ -0,0 +1,52 @@
@import './_base.css';
@import './_sizes.css';
@layer base {
.dbv-kit-spinner {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--dbv-kit-spinner-height);
height: var(--dbv-kit-spinner-height);
}
.dbv-kit-spinner--small {
width: var(--dbv-kit-spinner-small-height);
height: var(--dbv-kit-spinner-small-height);
}
.dbv-kit-spinner--medium {
width: var(--dbv-kit-spinner-medium-height);
height: var(--dbv-kit-spinner-medium-height);
}
.dbv-kit-spinner--large {
width: var(--dbv-kit-spinner-large-height);
height: var(--dbv-kit-spinner-large-height);
}
.dbv-kit-spinner--xlarge {
width: var(--dbv-kit-spinner-xlarge-height);
height: var(--dbv-kit-spinner-xlarge-height);
}
.dbv-kit-spinner__svg {
stroke-dasharray: 40px, 100px;
stroke-dashoffset: 5px;
stroke-width: var(--dbv-kit-spinner-stroke-width);
stroke: var(--dbv-kit-spinner-stroke-color);
stroke-linecap: var(--dbv-kit-spinner-stroke-linecap);
animation: var(--dbv-kit-animate-spin);
animation-delay: var(--dbv-kit-spinner-animation-delay);
}
.dbv-kit-spinner__circle {
animation: var(--dbv-kit-animate-stroke);
animation-delay: var(--dbv-kit-spinner-animation-delay);
@media screen and (prefers-reduced-motion: reduce) {
animation: none;
}
}
}
@@ -0,0 +1,23 @@
import clsx from 'clsx';
import './Spinner.css';
import type { ControlSize } from '../types/controls.js';
export interface SpinnerProps {
active?: boolean;
className?: string;
size?: ControlSize;
}
export function Spinner({ className, size, active = true }: SpinnerProps) {
if (!active) {
return null;
}
return (
<span className={clsx('dbv-kit-spinner', size && `dbv-kit-spinner--${size}`, className)}>
<svg className="dbv-kit-spinner__svg" viewBox="11 11 22 22">
<circle className="dbv-kit-spinner__circle" cx="22" cy="22" r="9" fill="none"></circle>
</svg>
</span>
);
}
@@ -0,0 +1,38 @@
@keyframes stroke {
0% {
stroke-dasharray: 1px, 100px;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 45px, 100px;
stroke-dashoffset: -10px;
}
100% {
stroke-dasharray: 17px, 100px;
stroke-dashoffset: -58px;
}
}
@keyframes spinning {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@layer base {
:root {
--dbv-kit-spinner-height: var(--dbv-kit-control-height-medium);
--dbv-kit-spinner-animation-duration: 1.8s;
--dbv-kit-spinner-animation-delay: -0.3s;
--dbv-kit-spinner-stroke-width: 2.5px;
--dbv-kit-spinner-stroke-color: var(--dbv-kit-color-primary-600);
--dbv-kit-spinner-stroke-linecap: butt;
--dbv-kit-animate-stroke: stroke var(--dbv-kit-spinner-animation-duration) linear infinite;
--dbv-kit-animate-spin: spinning var(--dbv-kit-spinner-animation-duration) cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
}
}
@@ -0,0 +1,8 @@
@layer base {
:root {
--dbv-kit-spinner-small-height: var(--dbv-kit-control-height-small);
--dbv-kit-spinner-medium-height: var(--dbv-kit-control-height-medium);
--dbv-kit-spinner-large-height: var(--dbv-kit-control-height-large);
--dbv-kit-spinner-xlarge-height: var(--dbv-kit-control-height-xlarge);
}
}
@@ -7,6 +7,8 @@
--dbv-kit-control-border-radius: var(--tw-radius-sm);
--dbv-kit-control-border-width: 1px;
--dbv-kit-control-disabled-opacity: 0.5;
--dbv-kit-control-disabled-foreground: var(--tw-color-gray-400);
--dbv-kit-control-disabled-background: var(--tw-color-gray-200);
/* Outline */
--dbv-kit-control-outline-color: var(--tw-color-blue-500);
+4 -1
View File
@@ -21,7 +21,8 @@ export {
type FocusTrapRegionProps,
} from '@ariakit/react';
export { Button, ButtonBase, type ButtonProps } from './Button/Button.js';
export { Button, ButtonBase, type ButtonProps, ButtonIcon, type ButtonIconProps } from './Button/Button.js';
export { IconButton, IconButtonBase, type IconButtonProps } from './IconButton/IconButton.js';
export { Checkbox, CheckboxBase, type CheckboxProps } from './Checkbox/Checkbox.js';
export { Input, InputBase, type InputProps } from './Input/Input.js';
export {
@@ -35,6 +36,8 @@ export {
type SelectItemProps,
} from './Select/Select.js';
export { SelectField, type SelectFieldProps, type SelectItem } from './Select/SelectField.js';
export { Spinner, type SpinnerProps } from './Spinner/Spinner.js';
export { Radio, RadioGroup, useRadioContext, useRadioStore, type RadioProviderProps, type RadioProps, type RadioGroupProps } from './Radio/index.js';
export { Icon, type IconProps } from './Icon/Icon.js';
export * from './utils/clsx.js';
export * from './ComponentProvider.js';
@@ -1,5 +1,5 @@
import type { Story } from '@ladle/react';
import { Button, type ButtonProps } from '../../../index.js';
import { Button, type ButtonProps, ButtonIcon } from '../../../index.js';
import { useState } from 'react';
export { Tokens } from './button-tokens.js';
@@ -48,17 +48,24 @@ export const Variants = () => (
<code>&lt;Button variant="primary"/&gt;</code>
</div>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<Button loading>Loading</Button>
<Button>Primary</Button>
<Button disabled>Disabled</Button>
</div>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<Button variant="secondary" loading>
Secondary
</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="secondary" disabled>
Disabled
</Button>
</div>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<Button variant="danger" loading>
Danger
</Button>
<Button variant="danger">Danger</Button>
<Button variant="danger" disabled>
Disabled
@@ -136,10 +143,10 @@ export const Sizes = () => (
export const Icons = () => (
<div>
<h2>Icons</h2>
<h3>&lt;Button.Icon&gt;</h3>
<h3>&lt;ButtonIcon&gt;</h3>
<code>.dbv-kit-button__icon</code>
<p>
To properly place an icon inside a button, you have to use Button.Icon component. That component will compensate outer padding to balance the
To properly place an icon inside a button, you have to use ButtonIcon component. That component will compensate outer padding to balance the
button view. You need to specify the placement property to adjust the icon position.
</p>
<dl>
@@ -148,7 +155,7 @@ export const Icons = () => (
</dl>
<div className="codeblock">
<code>
&lt;Button&gt; <br /> &nbsp;&nbsp;&lt;Button.Icon placement="start"/&gt;
&lt;Button&gt; <br /> &nbsp;&nbsp;&lt;ButtonIcon placement="start"/&gt;
<br />
&nbsp; Text
<br /> &lt;Button/&gt;
@@ -159,14 +166,14 @@ export const Icons = () => (
<h4>Compare buttons:</h4>
<div className="tw:flex tw:gap-4 tw:items-center tw:my-4">
<Button variant="secondary">
<Button.Icon placement="start">🧤</Button.Icon>
<ButtonIcon placement="start">🧤</ButtonIcon>
Text
</Button>
<Button variant="secondary">🧤 Text</Button>
</div>
<p>
The left button uses Button.Icon component and looks more balanced. If you feel that in your case it's not needed, feel free to not use the
<b> Button.Icon </b> component.
The left button uses ButtonIcon component and looks more balanced. If you feel that in your case it's not needed, feel free to not use the
<b> ButtonIcon </b> component.
</p>
</div>
@@ -183,12 +190,12 @@ export const Icons = () => (
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<Button size="small">
Love
<Button.Icon placement="end">❤️</Button.Icon>
<ButtonIcon placement="end">❤️</ButtonIcon>
</Button>
<Button className="tw:text-lime-300">
Have you seen
<Button.Icon className="w-2">
<ButtonIcon className="w-2">
<svg width="16" height="16" fill="none">
<g strokeWidth="0"></g>
<g strokeLinecap="round" strokeLinejoin="round"></g>
@@ -201,24 +208,24 @@ export const Icons = () => (
></path>
</g>
</svg>
</Button.Icon>
</ButtonIcon>
UFO?
</Button>
<Button size="large">
<Button.Icon placement="start">🎾</Button.Icon>
<ButtonIcon placement="start">🎾</ButtonIcon>
Tennis
</Button>
<Button size="xlarge">
<Button.Icon placement="start">🎾</Button.Icon>
<ButtonIcon placement="start">🎾</ButtonIcon>
Tennis is Love
<Button.Icon placement="end">❤️</Button.Icon>
<ButtonIcon placement="end">❤️</ButtonIcon>
</Button>
</div>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<Button loading>
<Button.Icon className="tw:w-8 tw:h-4" placement="start">
<ButtonIcon className="tw:w-8 tw:h-4" placement="start">
<svg width="16" height="16" fill="none">
<g strokeWidth="0"></g>
<g strokeLinecap="round" strokeLinejoin="round"></g>
@@ -231,34 +238,34 @@ export const Icons = () => (
></path>
</g>
</svg>
</Button.Icon>
</ButtonIcon>
UFO
</Button>
<Button variant="secondary" loading>
<Button.Icon placement="start">🎾</Button.Icon>
<ButtonIcon placement="start">🎾</ButtonIcon>
Tennis
</Button>
<Button disabled>
<Button.Icon placement="start">🎾</Button.Icon>
<ButtonIcon placement="start">🎾</ButtonIcon>
Tennis
</Button>
<Button variant="danger">
<Button.Icon placement="start">🎾</Button.Icon>
<ButtonIcon placement="start">🎾</ButtonIcon>
Tennis
</Button>
<Button>
<Button.Icon>🎾</Button.Icon>
<ButtonIcon>🎾</ButtonIcon>
</Button>
</div>
</div>
);
const CustomLoader = () => (
<Button.Icon placement="start">
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="tw:animate-spin tw:p-1">
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeDasharray="31.415, 31.415" />
</svg>
</Button.Icon>
</div>
);
export const Loading = () => {
@@ -280,9 +287,7 @@ export const Loading = () => {
and one of the dark colors for dark theme.
</span>
</p>
<div>
<code>--dbv-kit-btn-loader-animation:</code> var(--animate-spin); <span className="comment"> Button loader animation</span>
</div>
<label>
Enable loaders <input type="checkbox" checked={loading} onChange={toggleLoading} />
</label>
@@ -61,9 +61,13 @@ export const States = () => {
</Checkbox>
<Button onClick={() => setIndeterminate(prev => !prev)}>Set Indeterminate</Button>
<Checkbox indeterminate={indeterminate}>Indeterminate</Checkbox>
<Checkbox indeterminate={indeterminate} indeterminateIcon={<div className="tw:flex tw:relative tw:-top-[1px] tw:font-bold">▫</div>}>
<Checkbox
indeterminate={indeterminate}
indeterminateIcon={<div className="tw:flex tw:relative tw:-top-[2px] tw:-left-[1px] tw:font-bold">▫</div>}
>
Indeterminate Custom
</Checkbox>
Long text example:
<Checkbox>
Insert spaces when pressing <code>Tab</code>. This setting is overridden based on the file contents when{' '}
<a data-href="#" href="#">
@@ -0,0 +1,220 @@
import { Button, ButtonIcon, Icon, type IconProps } from '../../../index.js';
// All available icon names from the IconNames type
const iconNames = [
'replace',
'replace-all',
'match-word',
'case',
'regex',
'sort-asc',
'sort-desc',
'cross',
'sort-unknown',
'arrow-up',
'arrow-down',
] as Array<IconProps['name']>;
const sizes = ['small', 'medium', 'large'] as const;
export function Documentation() {
return (
<div>
<h1>Icon</h1>
<p>Icon component for displaying SVG icons using the symbol/use pattern.</p>
<h2>Usage</h2>
<p>Use the Icon component to display predefined SVG icons in your application.</p>
<h2>Anatomy</h2>
<p>
The Icon component consists of an SVG element that references icon symbols via the <code>&lt;use&gt;</code> element. Icons are sized
automatically based on the size prop and support color customization.
</p>
<pre className="codeblock">
{`
<svg class="dbv-kit-icon" width="16" height="16" viewBox="0 0 16 16">
<use href="#icon-search_sm" />
</svg>
`}
</pre>
<h2>Class names</h2>
<p>
The Icon component uses the following class names:
<ul>
<li>
<code>dbv-kit-icon</code>: Base class for the icon.
</li>
</ul>
</p>
<h2>Props</h2>
<table className="tw:table tw:w-full tw:border-collapse">
<thead>
<tr>
<th className="tw:py-2 tw:border tw:px-2">Prop</th>
<th className="tw:py-2 tw:border tw:px-2">Type</th>
<th className="tw:py-2 tw:border tw:px-2">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="tw:border tw:p-2">name</td>
<td className="tw:border tw:p-2">
<pre>IconNames (required)</pre>
</td>
<td className="tw:border tw:p-2">The name of the icon to display.</td>
</tr>
<tr>
<td className="tw:border tw:p-2">size</td>
<td className="tw:border tw:p-2">
<pre>small | medium | large</pre>
</td>
<td className="tw:border tw:p-2">Size of the icon. Default is 'small'.</td>
</tr>
<tr>
<td className="tw:border tw:p-2">className</td>
<td className="tw:border tw:p-2">
<pre>string | undefined</pre>
</td>
<td className="tw:border tw:p-2">Additional CSS class name.</td>
</tr>
<tr>
<td className="tw:border tw:p-2">color</td>
<td className="tw:border tw:p-2">
<pre>string | undefined</pre>
</td>
<td className="tw:border tw:p-2">Color of the icon.</td>
</tr>
<tr>
<td className="tw:border tw:p-2">style</td>
<td className="tw:border tw:p-2">
<pre>React.CSSProperties | undefined</pre>
</td>
<td className="tw:border tw:p-2">Inline styles for the icon.</td>
</tr>
</tbody>
</table>
</div>
);
}
export function AllIcons() {
return (
<div>
<h1>All Available Icons</h1>
<p>Here are all the available icons in the default (small) size:</p>
<div className="tw:grid tw:grid-cols-4 tw:gap-4 tw:mt-4">
{iconNames.map(iconName => (
<div key={iconName} className="tw:flex tw:flex-col tw:items-center tw:p-4">
<Icon name={iconName} />
<code className="tw:text-xs tw:mt-2">{iconName}</code>
</div>
))}
</div>
</div>
);
}
export function Sizes() {
return (
<div>
<h1>Icon Sizes</h1>
<p>Icons come in three different sizes: small (16px), medium (24px), and large (32px).</p>
<div className="tw:space-y-6 tw:mt-4">
{sizes.map(size => (
<div key={size} className="tw:space-y-2">
<h3 className="tw:text-lg tw:font-semibold tw:capitalize">
{size} ({size === 'small' ? '16px' : size === 'medium' ? '24px' : '32px'})
</h3>
<div className="tw:flex tw:gap-4 tw:flex-wrap">
{iconNames.map(iconName => (
<div key={`${size}-${iconName}`} className="tw:flex tw:flex-col tw:items-center tw:p-2">
<Icon name={iconName} size={size} />
<code className="tw:text-xs tw:mt-1">{iconName}</code>
</div>
))}
</div>
</div>
))}
</div>
</div>
);
}
export function WithColors() {
const colors = ['red', 'green', 'blue'];
return (
<div>
<h1>Icons with Colors</h1>
<p>Icons can be customized with different colors using the color prop.</p>
<div className="tw:space-y-4 tw:mt-4">
{colors.map(color => (
<div key={color} className="tw:space-y-2">
<h3 className="tw:text-lg tw:font-semibold" style={{ color }}>
Color: {color}
</h3>
<div className="tw:flex tw:gap-4 tw:flex-wrap">
{iconNames.slice(0, 5).map(iconName => (
<div key={`${color}-${iconName}`} className="tw:flex tw:flex-col tw:items-center tw:p-2 tw:border tw:rounded">
<Icon name={iconName} size="medium" color={color} />
<code className="tw:text-xs tw:mt-1">{iconName}</code>
</div>
))}
</div>
</div>
))}
</div>
</div>
);
}
export function UsageExamples() {
return (
<div>
<h1>Usage Examples</h1>
<div className="tw:space-y-6 tw:mt-4">
<div>
<h3 className="tw:text-lg tw:font-semibold">In Buttons</h3>
<Button>
<ButtonIcon placement="start">
<Icon name="cross" size="medium" color="white" className="tw:h-4 tw:w-4" />
</ButtonIcon>
Close
</Button>
</div>
<div>
<h3 className="tw:text-lg tw:font-semibold">As Status Indicators</h3>
<div className="tw:space-y-2">
<div className="tw:flex tw:items-center tw:gap-2">
<Icon name="sort-asc" size="medium" color="green" />
<span>Sorted ascending</span>
</div>
<div className="tw:flex tw:items-center tw:gap-2">
<Icon name="sort-desc" size="medium" color="red" />
<span>Sorted descending</span>
</div>
<div className="tw:flex tw:items-center tw:gap-2">
<Icon name="sort-unknown" size="medium" color="gray" />
<span>Unsorted</span>
</div>
</div>
</div>
<div>
<h3 className="tw:text-lg tw:font-semibold">With Custom Styling</h3>
<div className="tw:flex tw:items-center tw:gap-4">
<Icon
name="replace"
size="large"
style={{
filter: 'drop-shadow(2px 2px 4px rgba(0,0,0,0.2))',
transform: 'rotate(15deg)',
}}
/>
<Icon name="regex" size="medium" className="tw:opacity-50 tw:hover:opacity-100 tw:transition-opacity" />
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,210 @@
import { useState } from 'react';
import { IconButton } from '../../../index.js';
const example = `<IconButton
variant="primary" | "secondary" | "danger"
size="small" | "medium" | "large" | "xlarge"
loading={boolean}
disabled={boolean}
onClick={function}
aria-label="string"
>
{icon}
</IconButton>`;
export const Documentation = () => {
return (
<div className="tw:space-y-4">
<h1 className="tw:text-2xl tw:font-bold">IconButton</h1>
<p>IconButton is a button component that displays an icon. It supports various sizes and styles, and can be disabled or in a loading state.</p>
<pre className="codeblock">{example}</pre>
<h2 className="tw:text-xl tw:font-semibold">Classnames</h2>
<ul className="tw:list-disc tw:pl-5">
<li>
<code>dbv-kit-icon-button</code> - Main component class
</li>
<li>
<code>dbv-kit-icon-button--primary/secondary/danger</code> - Variant classes
</li>
<li>
<code>dbv-kit-icon-button--small/medium/large/xlarge</code> - Size classes
</li>
</ul>
<h2 className="tw:text-xl tw:font-semibold">CSS Tokens</h2>
<div className="tw:p-4 tw:rounded-md tw:overflow-auto">
<h3 className="tw:font-medium">Structure</h3>
<ul className="tw:pl-5 tw:mb-2">
<li>
<code>--dbv-kit-icon-btn-border-radius</code> - Controls button corner roundness
</li>
<li>
<code>--dbv-kit-icon-btn-border-width/style/color</code> - Border properties
</li>
<li>
<code>--dbv-kit-icon-btn-size</code> - Default button size (medium)
</li>
</ul>
<h3 className="tw:font-medium">Focus State</h3>
<ul className="tw:pl-5 tw:mb-2">
<li>
<code>--dbv-kit-icon-btn-outline-color/offset</code> - Focus outline appearance
</li>
</ul>
<h3 className="tw:font-medium">Colors</h3>
<ul className="tw:pl-5">
<li>
<code>--dbv-kit-icon-btn-foreground/background</code> - Default state colors
</li>
<li>
<code>--dbv-kit-icon-btn-foreground/background-hover</code> - Hover state colors
</li>
<li>
<code>--dbv-kit-icon-btn-foreground/background-active</code> - Active state colors
</li>
<li>
<code>--dbv-kit-btn-loader-color/base-color</code> - Loading spinner colors
</li>
</ul>
</div>
</div>
);
};
export const IconButtons = () => {
const [isLoading, setIsLoading] = useState(false);
const handleClick = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
}, 5000);
};
return (
<div className="tw:flex tw:flex-col tw:gap-4 tw:my-4 tw:items-center">
<div>
<h2>Primary</h2>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<IconButton variant="primary" size="small" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="primary" size="medium" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="primary" size="large" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="primary" size="xlarge" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
</div>
</div>
<div>
<h2>Secondary</h2>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<IconButton variant="secondary" size="small" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="secondary" size="medium" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="secondary" size="large" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="secondary" size="xlarge" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
</div>
</div>
<div>
<h2>Danger</h2>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<IconButton variant="danger" size="small" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="danger" size="medium" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="danger" size="large" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="danger" size="xlarge" aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
</div>
</div>
<div>
<h2>Disabled</h2>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<IconButton variant="primary" size="small" disabled aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="secondary" size="medium" disabled aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="danger" size="large" disabled aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
</div>
<h2>Loading</h2>
<div className="tw:flex tw:gap-4 tw:my-4 tw:items-center">
<IconButton variant="primary" size="small" loading aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="secondary" loading={isLoading} onClick={handleClick} aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton size="large" loading={isLoading} onClick={handleClick} aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
<IconButton variant="danger" size="xlarge" loading={isLoading} onClick={handleClick} aria-label="Add item">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
<circle cx="12" cy="12" r="12" fill="currentColor" />
</svg>
</IconButton>
</div>
</div>
</div>
);
};
@@ -0,0 +1,7 @@
.customLoader {
--dbv-kit-spinner-stroke-color: orange;
--dbv-kit-spinner-animation-duration: 5s;
--dbv-kit-animate-stroke: stroke var(--dbv-kit-spinner-animation-duration) linear infinite;
--dbv-kit-animate-spin: spinning var(--dbv-kit-spinner-animation-duration) cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
--dbv-kit-spinner-stroke-linecap: round;
}

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