From 212f38657a115e69252f6d5161e498ce61747ed8 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Thu, 4 Sep 2025 17:49:57 +0300 Subject: [PATCH 01/10] WIP --- .stylelintrc.json | 41 ++++++++++++++ package.json | 7 +++ src/lib/scss/common.scss | 111 +++++++++++--------------------------- src/lib/scss/details.scss | 4 +- src/lib/scss/mixins.scss | 45 ++++++++-------- 5 files changed, 105 insertions(+), 103 deletions(-) create mode 100644 .stylelintrc.json diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 00000000..53b86ca9 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,41 @@ +{ + "extends": ["stylelint-config-standard", "stylelint-config-standard-scss", "stylelint-config-rational-order"], + "plugins": [ + "stylelint-scss" + ], + "rules": { + "at-rule-no-unknown": null, + "selector-no-vendor-prefix": null, + "scss/at-mixin-argumentless-call-parentheses": null, + "scss/dollar-variable-empty-line-before": null, + "scss/at-rule-no-unknown": true, + "media-feature-range-notation": null, + "property-no-vendor-prefix": null, + "selector-class-pattern": [ + "^[a-z0-9]+(?:-[a-z0-9]+)*(?:__(?:[a-z0-9]+(?:-[a-z0-9]+)*))*(?:_(?:[a-z0-9]+(?:-[a-z0-9]+)*)(?:_[a-z0-9]+(?:-[a-z0-9]+)*)?)?$", + { + "resolveNestedSelectors": true, + "message": "Expected kebab-case or BEM: block-name, block-name__elem-name(__sub-elem…), block-name_mod-name[_mod-val], block-name__elem-name_mod-name[_mod-val]" + } + ], + "scss/at-mixin-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected mixin name to be kebab-case (my-mixin) or camelCase (myMixin)" + } + ], + "custom-property-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected variable name to be kebab-case (my-variable) or camelCase (myVariable)" + } + ], + "scss/dollar-variable-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected variable name to be kebab-case (my-variable) or camelCase (myVariable)" + } + ] + + } +} diff --git a/package.json b/package.json index 01dc887b..bd008195 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,12 @@ "react-router-dom": "6.22.3", "react-transition-group": "^4.4.5", "sass": "^1.72.0", + "stylelint": "^16.21.0", + "stylelint-config-rational-order": "^0.1.2", + "stylelint-config-standard": "^38.0.0", + "stylelint-config-standard-scss": "^15.0.1", + "stylelint-order": "^7.0.0", + "stylelint-scss": "^6.12.1", "tsup": "^8.3.6", "typescript": "^5.7.3", "typescript-eslint": "^8.23.0", @@ -107,6 +113,7 @@ "scripts": { "lint": "eslint 'src/**/*.{js,jsx}' --quiet", "lint:fix": "eslint 'src/**/*.{js,jsx}' --fix", + "stylelint": "stylelint '**/*.{css,scss}'", "prettier": "prettier --check 'src/**/*.{js,jsx,scss}'", "prettier:fix": "prettier --write 'src/**/*.{js,jsx,scss}'", "build-storybook": "build-storybook", diff --git a/src/lib/scss/common.scss b/src/lib/scss/common.scss index 46f1d224..85b7584f 100644 --- a/src/lib/scss/common.scss +++ b/src/lib/scss/common.scss @@ -20,8 +20,6 @@ --mischkaColor: #{colors.$mischka}; } -/* =========== GENERAL ============= */ - #root { z-index: 1; display: flex; @@ -30,6 +28,7 @@ isolation: isolate; } +/* stylelint-disable-next-line selector-id-pattern */ #overlay_container { position: fixed; bottom: 0; @@ -62,7 +61,9 @@ button { input, textarea { + padding: 0; overflow-x: hidden; + color: inherit; font-weight: normal; font-size: 15px; font-family: Roboto, sans-serif; @@ -70,10 +71,8 @@ textarea { line-height: 18px; white-space: nowrap; text-overflow: ellipsis; - border: 0; - color: inherit; background-color: transparent; - padding: 0; + border: 0; resize: none; &::placeholder { @@ -114,8 +113,8 @@ textarea { .link { color: colors.$cornflowerBlue; - cursor: pointer; line-height: 20px; + cursor: pointer; &:hover { text-decoration: underline; @@ -124,10 +123,10 @@ textarea { } .warning-text { - color: colors.$amaranth; padding: 5px 0; - line-height: 1.5; + color: colors.$amaranth; font-size: 13px; + line-height: 1.5; } [class*='igz-transition'] { @@ -227,7 +226,7 @@ a { @include mixins.displayFlex; @media screen and (min-width: 1300px) { - padding: 15px 64px 15px; + padding: 15px 64px; } &__header { @@ -589,8 +588,8 @@ a { &::before { background: linear-gradient( 90deg, - rgba(255, 255, 255, 0) 0%, - rgba(245, 247, 255, 1) 100% + rgb(255 255 255 / 0%) 0%, + rgb(245 247 255 / 100%) 100% ); } } @@ -609,8 +608,8 @@ a { &::before { background: linear-gradient( 90deg, - rgba(255, 255, 255, 0) 0%, - rgba(245, 247, 255, 1) 100% + rgb(255 255 255 / 0%) 0%, + rgb(245 247 255 / 100%) 100% ); } } @@ -698,7 +697,7 @@ a { @include mixins.tableHeader; &:first-child { - border-radius: 4px 0 0 0; + border-radius: 4px 0 0; } &:last-child { @@ -776,9 +775,9 @@ a { display: flex; align-items: center; min-height: $tableHeaderHeight; - border-bottom: borders.$primaryBorder; - background-color: colors.$white; padding: 5px 0; + background-color: colors.$white; + border-bottom: borders.$primaryBorder; &.form-table__row_excluded { .form-table__cell { @@ -831,17 +830,17 @@ a { } .form-table__header-row { - border-top: borders.$primaryBorder; - font-size: 18px; - font-weight: bold; top: 0; + font-weight: bold; + font-size: 18px; + border-top: borders.$primaryBorder; } .form-table__sub-header-row { - border: unset; - font-size: 16px; - font-weight: bold; top: $tableHeaderHeight; + font-weight: bold; + font-size: 16px; + border: unset; } .form-table__action-row { @@ -871,9 +870,9 @@ a { .form-table__cell { display: flex; - overflow: hidden; align-items: center; padding: 3px 10px; + overflow: hidden; color: colors.$primary; &.disabled { @@ -886,9 +885,9 @@ a { &.form-table__name_with-asterisk { &::after { - content: ' * '; - color: colors.$amaranth; margin-right: 10px; + color: colors.$amaranth; + content: ' * '; } } } @@ -921,10 +920,10 @@ a { .form-table__actions-cell { flex: 0 1 auto; - visibility: hidden; justify-content: flex-end; min-width: variables.$actionsCellWidth; padding: 0; + visibility: hidden; & > * { margin: 0 5px 0 0; @@ -954,33 +953,31 @@ a { } } -/* =========== HIDDEN CHIPS ============= */ - .chip-block-hidden { position: fixed; - display: flex; - flex-direction: column; top: unset; right: unset; - left: unset; bottom: unset; + left: unset; + z-index: 9; + display: flex; + flex-direction: column; width: min-content; - height: min-content; min-width: 250px; max-width: 100%; + height: min-content; max-height: 100%; padding: 10px; background-color: colors.$white; border-radius: variables.$mainBorderRadius; box-shadow: shadows.$hiddenChipsBlockShadow; - z-index: 9; opacity: 0; &__scrollable-container { - overflow: auto; display: flex; - width: 100%; flex-flow: row wrap; + width: 100%; + overflow: auto; } &_bottom { @@ -1010,47 +1007,3 @@ a { opacity: 1; } } - -/* =========== SORT ============= */ - -.sortable-header { - &-cell { - position: relative; - border: 0; - border-radius: 0; - cursor: pointer; - - .sort-icon { - position: absolute; - top: auto; - right: 2px; - bottom: auto; - display: none; - } - - &_active { - background-color: colors.$alabaster; - - .sort-icon { - display: block; - } - } - - &:hover { - .sort-icon { - display: block; - } - } - - label { - cursor: pointer; - } - } - - &-label { - position: relative; - display: flex; - align-items: center; - padding-right: 25px; - } -} diff --git a/src/lib/scss/details.scss b/src/lib/scss/details.scss index a2a3536e..836d9c63 100644 --- a/src/lib/scss/details.scss +++ b/src/lib/scss/details.scss @@ -38,7 +38,7 @@ flex-wrap: wrap; align-items: flex-start; justify-content: flex-end; - margin: 0 0 1em 0; + margin: 0 0 1em; &-wrapper { position: sticky; @@ -101,7 +101,7 @@ margin-right: auto; h3 { - margin: 0 0 5px 0; + margin: 0 0 5px; font-size: 24px; line-height: 28px; } diff --git a/src/lib/scss/mixins.scss b/src/lib/scss/mixins.scss index 60d0e6e8..76ad6fd0 100644 --- a/src/lib/scss/mixins.scss +++ b/src/lib/scss/mixins.scss @@ -8,7 +8,7 @@ left: 0; } -@mixin displayFlex { +@mixin jobsFlex { display: flex; flex-grow: 1; flex-shrink: 1; @@ -94,8 +94,8 @@ @mixin statusState($color, $bordered) { display: inline-block; width: 8px; - height: 8px; min-width: 8px; + height: 8px; border-radius: 50%; @if $bordered == true { @@ -394,9 +394,9 @@ } @mixin tableHeader { - background-color: colors.$magnoliaWhite; font-weight: bold; font-size: 14px; + background-color: colors.$magnoliaWhite; } @mixin resetSpaces { @@ -534,7 +534,7 @@ &-wrapper { display: flex; width: 100%; - margin: 0 -1px 0 -1px; + margin: 0 -1px; border: borders.$primaryBorder; .select { @@ -1027,10 +1027,10 @@ } @mixin fieldWrapper { + position: relative; display: flex; flex: 1; flex-flow: row nowrap; - position: relative; width: 100%; color: colors.$primary; background-color: transparent; @@ -1042,8 +1042,8 @@ position: relative; display: flex; flex-flow: column nowrap; - height: 100%; width: 100%; + height: 100%; &__label { display: flex; @@ -1075,8 +1075,8 @@ @include fieldWrapper; &-disabled { - border: borders.$disabledBorder; color: colors.$spunPearl; + border: borders.$disabledBorder; cursor: not-allowed; } @@ -1133,26 +1133,26 @@ @mixin radioCheckReadonly { input { - pointer-events: none; opacity: 0.5; + pointer-events: none; ~ label, ~ .label { - pointer-events: none; opacity: 0.5; + pointer-events: none; } } } @mixin radioCheckField { position: relative; + margin: 0; + color: colors.$malibu; background: colors.$white; border: 1px solid colors.$malibu; - color: colors.$malibu; - appearance: none; - margin: 0; outline: 0; cursor: pointer; + appearance: none; &:checked { &:hover { @@ -1160,20 +1160,20 @@ &:disabled { color: colors.$spunPearl; - border-color: currentColor; + border-color: currentcolor; } } } &:disabled { color: colors.$spunPearl; - border-color: currentColor; + border-color: currentcolor; cursor: not-allowed; pointer-events: none; &:hover { color: colors.$spunPearl; - border-color: currentColor; + border-color: currentcolor; } ~ label, @@ -1187,6 +1187,7 @@ 20% { box-shadow: 0 0 0 0 rgba(colors.$cornflowerBlue, 0.5); } + 100% { box-shadow: 0 0 0 6px rgba(colors.$cornflowerBlue, 0); } @@ -1200,26 +1201,26 @@ &:hover { color: colors.$cornflowerBlue; - border-color: currentColor; + border-color: currentcolor; } } ~ label, ~ .label { + position: relative; display: flex; flex: 1; align-items: center; - position: relative; - cursor: pointer; - font-size: 1em; - padding: 0 0 0 0.45em; height: inherit; - user-select: none; + padding: 0 0 0 0.45em; + font-size: 1em; white-space: nowrap; + cursor: pointer; + user-select: none; } } -//TODO: Delete after removing Textarea and Input and using DRC components +// TODO: Delete after removing Textarea and Input and using DRC components @mixin fieldWrapperOld { position: relative; width: 100%; From 7a89a21a78f1207ab90ae0b6172271dba057b819 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Fri, 5 Sep 2025 15:43:44 +0300 Subject: [PATCH 02/10] Impl [UI] update "stylelint' libraries --- package.json | 2 +- .../components/ActionsMenu/actionsMenu.scss | 16 +++---- src/lib/components/Backdrop/Backdrop.scss | 2 +- src/lib/components/Button/Button.scss | 2 +- src/lib/components/ChipCell/chipCell.scss | 2 +- .../components/FormCheckBox/formCheckBox.scss | 18 ++++---- .../FormChipCell/FormChip/formChip.scss | 4 +- .../FormChipCell/NewChipForm/newChipForm.scss | 2 +- .../components/FormChipCell/formChipCell.scss | 2 +- .../components/FormCombobox/formCombobox.scss | 8 ++-- .../InputNumberButtons.scss | 4 +- src/lib/components/FormInput/formInput.scss | 2 +- src/lib/components/FormRadio/FormRadio.scss | 6 +-- src/lib/components/FormSelect/formSelect.scss | 6 +-- .../components/FormTextarea/formTextarea.scss | 4 +- src/lib/components/FormToggle/formToggle.scss | 14 +++--- src/lib/components/Modal/Modal.scss | 45 +++++++++---------- .../components/PopUpDialog/popUpDialog.scss | 2 +- src/lib/components/Tip/tip.scss | 2 +- src/lib/components/Tooltip/tooltip.scss | 6 +-- src/lib/components/Wizard/Wizard.scss | 8 ++-- .../Wizard/WizardSteps/WizardSteps.scss | 40 ++++++++--------- .../elements/SelectOption/selectOption.scss | 12 ++--- .../elements/TableLinkCell/tableLinkCell.scss | 6 +-- src/lib/scss/common.scss | 4 +- src/lib/scss/fonts.scss | 30 ++++++------- src/lib/scss/shadows.scss | 2 +- 27 files changed, 125 insertions(+), 126 deletions(-) diff --git a/package.json b/package.json index bd008195..13952a29 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "scripts": { "lint": "eslint 'src/**/*.{js,jsx}' --quiet", "lint:fix": "eslint 'src/**/*.{js,jsx}' --fix", - "stylelint": "stylelint '**/*.{css,scss}'", + "stylelint": "stylelint 'src/**/*.{css,scss}'", "prettier": "prettier --check 'src/**/*.{js,jsx,scss}'", "prettier:fix": "prettier --write 'src/**/*.{js,jsx,scss}'", "build-storybook": "build-storybook", diff --git a/src/lib/components/ActionsMenu/actionsMenu.scss b/src/lib/components/ActionsMenu/actionsMenu.scss index b5024b33..c23f9fb2 100644 --- a/src/lib/components/ActionsMenu/actionsMenu.scss +++ b/src/lib/components/ActionsMenu/actionsMenu.scss @@ -13,17 +13,17 @@ display: none; align-items: center; justify-content: center; - background-color: colors.$ghostWhite; height: 100%; + background-color: colors.$ghostWhite; - &:before { - content: ''; - width: 30px; - height: 100%; + &::before { position: absolute; - display: block; left: -30px; - background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(245, 247, 255, 1) 100%); + display: block; + width: 30px; + height: 100%; + background: linear-gradient(90deg, rgb(255 255 255 / 0%) 0%, rgb(245 247 255 / 100%) 100%); + content: ''; } .actions-menu { @@ -53,8 +53,8 @@ } &__list { - list-style-type: none; margin: 0; padding: 0; + list-style-type: none; } } diff --git a/src/lib/components/Backdrop/Backdrop.scss b/src/lib/components/Backdrop/Backdrop.scss index 036a91b1..271ee7cb 100644 --- a/src/lib/components/Backdrop/Backdrop.scss +++ b/src/lib/components/Backdrop/Backdrop.scss @@ -4,10 +4,10 @@ position: fixed; top: 0; left: 0; + z-index: 9; width: 100vw; height: 100vh; background-color: colors.$black; - z-index: 9; &-transition { &-enter { diff --git a/src/lib/components/Button/Button.scss b/src/lib/components/Button/Button.scss index 0f199c63..e1446119 100644 --- a/src/lib/components/Button/Button.scss +++ b/src/lib/components/Button/Button.scss @@ -34,7 +34,7 @@ svg { & > * { - fill: currentColor; + fill: currentcolor; } } diff --git a/src/lib/components/ChipCell/chipCell.scss b/src/lib/components/ChipCell/chipCell.scss index 90c6d0f8..e960f355 100644 --- a/src/lib/components/ChipCell/chipCell.scss +++ b/src/lib/components/ChipCell/chipCell.scss @@ -30,7 +30,7 @@ display: flex; align-items: center; justify-content: center; - margin: 2px 0 2px 0; + margin: 2px 0; border-radius: 32px; &-background { diff --git a/src/lib/components/FormCheckBox/formCheckBox.scss b/src/lib/components/FormCheckBox/formCheckBox.scss index 007efbd6..85432a18 100644 --- a/src/lib/components/FormCheckBox/formCheckBox.scss +++ b/src/lib/components/FormCheckBox/formCheckBox.scss @@ -21,27 +21,27 @@ @include mixins.radioCheckField; &::before { - content: ''; - display: block; position: absolute; top: 1px; left: 5px; + display: block; width: 6px; height: 11px; - border-style: solid; border-color: colors.$white; + border-style: solid; border-width: 0 2px 2px 0; transform: rotate(45deg); + content: ''; } &:checked { - background: currentColor; + background: currentcolor; &:hover { - background: currentColor; + background: currentcolor; &:disabled { - background: currentColor; + background: currentcolor; } } } @@ -71,11 +71,11 @@ ~ label { &.highlighted { - background-color: colors.$mischka; - font-size: 12px; - font-weight: bold; margin-left: 10px; padding: 4px 8px; + font-weight: bold; + font-size: 12px; + background-color: colors.$mischka; border-radius: 4px; } } diff --git a/src/lib/components/FormChipCell/FormChip/formChip.scss b/src/lib/components/FormChipCell/FormChip/formChip.scss index 70b44364..de8e1913 100644 --- a/src/lib/components/FormChipCell/FormChip/formChip.scss +++ b/src/lib/components/FormChipCell/FormChip/formChip.scss @@ -14,8 +14,8 @@ } &_invisible { - visibility: hidden; height: 30px; + visibility: hidden; } &__content { @@ -24,8 +24,8 @@ &-item { flex: 1 1 50%; - max-width: fit-content; align-self: flex-start; + max-width: fit-content; } } diff --git a/src/lib/components/FormChipCell/NewChipForm/newChipForm.scss b/src/lib/components/FormChipCell/NewChipForm/newChipForm.scss index 9010f666..8a48aaee 100644 --- a/src/lib/components/FormChipCell/NewChipForm/newChipForm.scss +++ b/src/lib/components/FormChipCell/NewChipForm/newChipForm.scss @@ -5,7 +5,7 @@ &-container { display: inline-flex; max-width: 100%; - margin: 2px 0 2px 0; + margin: 2px 0; padding: 0 8px; font-size: 14px; line-height: 22px; diff --git a/src/lib/components/FormChipCell/formChipCell.scss b/src/lib/components/FormChipCell/formChipCell.scss index f72de368..8ae52fae 100644 --- a/src/lib/components/FormChipCell/formChipCell.scss +++ b/src/lib/components/FormChipCell/formChipCell.scss @@ -39,7 +39,7 @@ display: flex; align-items: center; justify-content: center; - margin: 2px 0 2px 0; + margin: 2px 0; border-radius: 32px; &-background { diff --git a/src/lib/components/FormCombobox/formCombobox.scss b/src/lib/components/FormCombobox/formCombobox.scss index cbc1a45e..85878bba 100644 --- a/src/lib/components/FormCombobox/formCombobox.scss +++ b/src/lib/components/FormCombobox/formCombobox.scss @@ -11,8 +11,8 @@ &__icons { .form-field-combobox__icon { - cursor: pointer; padding: 0; + cursor: pointer; transition: transform 200ms linear; &_open { @@ -43,8 +43,8 @@ display: flex; flex: 1; align-items: center; - cursor: pointer; height: 100%; + cursor: pointer; } } @@ -71,8 +71,8 @@ display: flex; align-items: center; margin: 0 9px; - border-bottom: borders.$dividerBorder; background-color: colors.$white; + border-bottom: borders.$dividerBorder; } } @@ -86,9 +86,9 @@ } &-list { + min-width: 140px; margin: 0; padding: 0; - min-width: 140px; list-style-type: none; &-option { diff --git a/src/lib/components/FormInput/InputNumberButtons/InputNumberButtons.scss b/src/lib/components/FormInput/InputNumberButtons/InputNumberButtons.scss index 02b24ee7..708c77a3 100644 --- a/src/lib/components/FormInput/InputNumberButtons/InputNumberButtons.scss +++ b/src/lib/components/FormInput/InputNumberButtons/InputNumberButtons.scss @@ -15,10 +15,10 @@ &__button { display: flex; - width: 100%; - height: calc(50% + 1px); align-items: center; justify-content: center; + width: 100%; + height: calc(50% + 1px); padding: 0; background-color: colors.$wildSand; cursor: pointer; diff --git a/src/lib/components/FormInput/formInput.scss b/src/lib/components/FormInput/formInput.scss index f761158f..6424676e 100644 --- a/src/lib/components/FormInput/formInput.scss +++ b/src/lib/components/FormInput/formInput.scss @@ -6,8 +6,8 @@ width: 100%; input { - height: inherit; width: 100%; + height: inherit; padding: 12px 16px; } diff --git a/src/lib/components/FormRadio/FormRadio.scss b/src/lib/components/FormRadio/FormRadio.scss index 49c4f09f..02e8a773 100644 --- a/src/lib/components/FormRadio/FormRadio.scss +++ b/src/lib/components/FormRadio/FormRadio.scss @@ -5,8 +5,8 @@ display: inline-flex; align-items: center; justify-content: flex-start; - color: colors.$primary; margin-right: 15px; + color: colors.$primary; &_readonly { @include mixins.radioCheckReadonly; @@ -20,16 +20,16 @@ @include mixins.radioCheckField; &::before { - content: ''; position: absolute; top: 2px; left: 2px; width: 10px; height: 10px; border-radius: 50%; + box-shadow: inset 1em 1em currentcolor; transform: scale(0); transition: transform 0.2s ease-in-out; - box-shadow: inset 1em 1em currentColor; + content: ''; } &:checked { diff --git a/src/lib/components/FormSelect/formSelect.scss b/src/lib/components/FormSelect/formSelect.scss index 767e896b..04dfc801 100644 --- a/src/lib/components/FormSelect/formSelect.scss +++ b/src/lib/components/FormSelect/formSelect.scss @@ -39,8 +39,8 @@ &-value { display: block; - font-size: 15px; overflow: hidden; + font-size: 15px; white-space: nowrap; text-overflow: ellipsis; } @@ -68,11 +68,11 @@ } .options-list { + max-height: 250px; margin: 0; padding: 0; - list-style-type: none; - max-height: 250px; overflow-y: auto; + list-style-type: none; &__body { width: 100%; diff --git a/src/lib/components/FormTextarea/formTextarea.scss b/src/lib/components/FormTextarea/formTextarea.scss index 4caf952c..e2aab1ef 100644 --- a/src/lib/components/FormTextarea/formTextarea.scss +++ b/src/lib/components/FormTextarea/formTextarea.scss @@ -5,8 +5,8 @@ width: 100%; textarea { - height: inherit; width: 100%; + height: inherit; padding: 12px 16px; white-space: normal; } @@ -21,9 +21,9 @@ } &__counter { + margin-top: 5px; color: colors.$topaz; font-size: 12px; - margin-top: 5px; text-align: right; } } diff --git a/src/lib/components/FormToggle/formToggle.scss b/src/lib/components/FormToggle/formToggle.scss index 69ef4dc5..8810462d 100644 --- a/src/lib/components/FormToggle/formToggle.scss +++ b/src/lib/components/FormToggle/formToggle.scss @@ -5,23 +5,23 @@ position: relative; &__switch { - height: 24px; - width: 48px; display: flex; - cursor: pointer; align-items: center; + width: 48px; + height: 24px; background-color: colors.$alto; border-radius: 20px; + cursor: pointer; transition: all 0.2s ease; - &:before { - content: ''; + &::before { width: 20px; height: 20px; background-color: colors.$white; border-radius: 50%; transform: translateX(2px); transition: all 0.2s ease; + content: ''; } } @@ -40,9 +40,9 @@ &:disabled { & + * .form-field-toggle__switch { + cursor: default; opacity: 0.5; pointer-events: none; - cursor: default; } } @@ -50,7 +50,7 @@ & + * .form-field-toggle__switch { background-color: colors.$malibu; - &:before { + &::before { transform: translateX(26px); } } diff --git a/src/lib/components/Modal/Modal.scss b/src/lib/components/Modal/Modal.scss index 91f36d5b..16222379 100644 --- a/src/lib/components/Modal/Modal.scss +++ b/src/lib/components/Modal/Modal.scss @@ -6,14 +6,14 @@ position: fixed; top: 50%; left: 50%; + z-index: 9; width: 100%; - height: 660px; - max-width: 96%; min-width: 300px; + max-width: 96%; + height: 660px; max-height: 96%; outline: 0; transform: translate(-50%, -50%); - z-index: 9; @media screen and (min-width: 1200px) { width: 1000px; @@ -43,41 +43,41 @@ } &__content { + position: relative; display: flex; flex-flow: column nowrap; - position: relative; - min-height: inherit; - height: 100%; width: 100%; + height: 100%; + min-height: inherit; max-height: 100%; + text-align: left; background-color: colors.$white; border-radius: variables.$modalBorderRadius; box-shadow: 0 6px 26px rgba(colors.$black, 0.2); - text-align: left; } &__header { position: relative; - border-bottom: borders.$primaryBorder; - min-height: 92px; - padding: 1rem 3rem; display: flex; + flex-direction: column; align-items: center; justify-content: center; - flex-direction: column; + min-height: 92px; + padding: 1rem 3rem; + border-bottom: borders.$primaryBorder; &-title { + margin: 0; color: colors.$primary; font-size: 2em; text-transform: capitalize; - margin: 0; } &-sub-title { + margin: 10px 0 0; color: colors.$topaz; - font-size: 1.5em; font-weight: 500; - margin: 10px 0 0; + font-size: 1.5em; } &-preview-text { @@ -95,11 +95,10 @@ } &__body { - overflow-y: auto; - overflow-x: hidden; flex: 1 0; - padding: 1.5rem 2rem 0; margin-bottom: 1rem; + padding: 1.5rem 2rem 0; + overflow: hidden auto; } &__footer { @@ -107,14 +106,14 @@ flex-flow: row nowrap; flex-shrink: 0; justify-content: space-between; - padding: 1rem 2rem; min-height: 50px; + padding: 1rem 2rem; &-actions { display: flex; flex: 1 0 auto; - justify-content: flex-end; align-items: center; + justify-content: flex-end; & > *:not(:last-child) { margin-right: 10px; @@ -124,25 +123,25 @@ &-transition { &-enter { - opacity: 0; transform: translate(-50%, calc(100vh)); + opacity: 0; } &-enter-active, &-enter-done { - opacity: 1; transform: translate(-50%, -50%); + opacity: 1; transition: all 0.3s ease-in-out; } &-exit { - opacity: 1; transform: translate(-50%, -50%); + opacity: 1; } &-exit-active { - opacity: 0; transform: translate(-50%, -70%); + opacity: 0; transition: all 0.3s ease-in-out; } } diff --git a/src/lib/components/PopUpDialog/popUpDialog.scss b/src/lib/components/PopUpDialog/popUpDialog.scss index 9e4ac425..bd359fb6 100644 --- a/src/lib/components/PopUpDialog/popUpDialog.scss +++ b/src/lib/components/PopUpDialog/popUpDialog.scss @@ -20,13 +20,13 @@ position: fixed; top: 0; left: 0; + z-index: 9; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background: colors.$mineshaftTwo; - z-index: 9; &.custom-position { width: auto; diff --git a/src/lib/components/Tip/tip.scss b/src/lib/components/Tip/tip.scss index 32387da6..f756141c 100644 --- a/src/lib/components/Tip/tip.scss +++ b/src/lib/components/Tip/tip.scss @@ -10,13 +10,13 @@ .tip { position: fixed; + z-index: 9; display: block; padding: 10px; color: colors.$white; white-space: pre-line; background: colors.$primary; border-radius: 4px; - z-index: 9; &-wrapper { display: inline-flex; diff --git a/src/lib/components/Tooltip/tooltip.scss b/src/lib/components/Tooltip/tooltip.scss index 8625c218..1bc29b2d 100644 --- a/src/lib/components/Tooltip/tooltip.scss +++ b/src/lib/components/Tooltip/tooltip.scss @@ -1,11 +1,11 @@ .tooltip { position: fixed; + z-index: 9; + display: flex; + max-width: 400px; font-weight: 400; font-size: 15px; line-height: 1.4; - display: flex; - max-width: 400px; - z-index: 9; } .fade { diff --git a/src/lib/components/Wizard/Wizard.scss b/src/lib/components/Wizard/Wizard.scss index 9e43738d..251c7a56 100644 --- a/src/lib/components/Wizard/Wizard.scss +++ b/src/lib/components/Wizard/Wizard.scss @@ -2,8 +2,8 @@ .modal__body { display: flex; flex-flow: column nowrap; - overflow: hidden; padding: 0; + overflow: hidden; @media screen and (min-width: 1200px) { flex-flow: row nowrap; @@ -11,10 +11,10 @@ } .wizard-form__content-container { - overflow-y: auto; - height: 100%; width: 100%; + height: 100%; padding: 0 2rem 1.5rem; + overflow-y: auto; @media screen and (min-width: 1200px) { padding: 1.5rem 2rem 1.5rem 1rem; @@ -27,8 +27,8 @@ .wizard-form__hidden-content-item { position: absolute; - visibility: hidden; height: 0; + visibility: hidden; opacity: 0; pointer-events: none; } diff --git a/src/lib/components/Wizard/WizardSteps/WizardSteps.scss b/src/lib/components/Wizard/WizardSteps/WizardSteps.scss index 637b2961..439f21e3 100644 --- a/src/lib/components/Wizard/WizardSteps/WizardSteps.scss +++ b/src/lib/components/Wizard/WizardSteps/WizardSteps.scss @@ -3,15 +3,15 @@ .wizard-steps { display: flex; flex-flow: row nowrap; - background-color: colors.$white; min-width: 260px; margin: 1.5rem 0; padding: 0 2rem; + background-color: colors.$white; @media screen and (min-width: 1200px) { flex-flow: column nowrap; - overflow-y: auto; padding: 0 1rem; + overflow-y: auto; & > *:not(:last-child) { margin-bottom: 10px; @@ -21,15 +21,15 @@ .wizard-steps { &__item { display: block; - background-color: inherit; + width: 100%; + height: auto; + min-height: 52px; + padding: 8px; color: colors.$primary; + font-size: 1em; + background-color: inherit; border: 0; border-radius: 8px; - font-size: 1em; - padding: 8px; - min-height: 52px; - height: auto; - width: 100%; @media screen and (min-width: 1200px) { display: flex; @@ -37,25 +37,25 @@ justify-content: flex-start; & > * { - text-align: left; white-space: normal; + text-align: left; } } .wizard-steps__indicator { - border-color: colors.$malibu; color: colors.$malibu; background-color: inherit; + border-color: colors.$malibu; } &.wizard-steps__item_active { - background-color: colors.$malibuTwo; color: colors.$cornflowerBlue; + background-color: colors.$malibuTwo; .wizard-steps__indicator { - border-color: transparent; color: colors.$white; background-color: colors.$malibu; + border-color: transparent; } } @@ -67,20 +67,20 @@ } .wizard-steps__indicator { - border-color: colors.$amaranth; color: colors.$amaranth; background-color: inherit; + border-color: colors.$amaranth; } } &:disabled { - border: 0; color: colors.$spunPearl; + border: 0; .wizard-steps__indicator { - border-color: colors.$spunPearl; color: colors.$spunPearl; background-color: inherit; + border-color: colors.$spunPearl; } } } @@ -89,17 +89,17 @@ display: inline-flex; align-items: center; justify-content: center; - border: 2px solid transparent; - border-radius: 50%; - padding: 10px; - margin: 0 0 10px 0; width: 36px; height: 36px; + margin: 0 0 10px; + padding: 10px; + border: 2px solid transparent; + border-radius: 50%; @media screen and (min-width: 1200px) { flex-flow: row nowrap; - text-align: left; margin: 0 10px 0 0; + text-align: left; } } } diff --git a/src/lib/elements/SelectOption/selectOption.scss b/src/lib/elements/SelectOption/selectOption.scss index 841f3469..8a6ce936 100644 --- a/src/lib/elements/SelectOption/selectOption.scss +++ b/src/lib/elements/SelectOption/selectOption.scss @@ -4,15 +4,15 @@ .select { &__item { display: flex; - align-items: center; flex-flow: row wrap; + align-items: center; width: 100%; min-height: 45px; padding: 10px 15px; &.multiple { - padding: 0 15px; min-height: 0; + padding: 0 15px; input[type='checkbox'] ~ label { padding-top: 16px; @@ -26,8 +26,8 @@ .form-field-checkbox { flex: 1; - height: 100%; width: 100%; + height: 100%; } &:hover { @@ -61,24 +61,24 @@ &-label { display: flex; + flex: 1; flex-flow: row wrap; align-items: center; justify-content: flex-start; - flex: 1; } &-main-label { - width: 100%; display: flex; flex-flow: row nowrap; align-items: center; justify-content: flex-start; + width: 100%; } &-sub-label { + width: 100%; margin-top: 5px; font-size: 13px; - width: 100%; } &-icon { diff --git a/src/lib/elements/TableLinkCell/tableLinkCell.scss b/src/lib/elements/TableLinkCell/tableLinkCell.scss index cacc2117..473cb9b8 100644 --- a/src/lib/elements/TableLinkCell/tableLinkCell.scss +++ b/src/lib/elements/TableLinkCell/tableLinkCell.scss @@ -44,13 +44,13 @@ display: flex; align-items: center; justify-content: space-between; + width: max-content; + min-width: 100%; + margin-top: 5px; font-weight: normal; font-size: 12px; font-family: Roboto, sans-serif; font-style: normal; - margin-top: 5px; - width: max-content; - min-width: 100%; & > span { &:not(:last-child) { diff --git a/src/lib/scss/common.scss b/src/lib/scss/common.scss index 85b7584f..b2310464 100644 --- a/src/lib/scss/common.scss +++ b/src/lib/scss/common.scss @@ -218,10 +218,10 @@ a { position: relative; flex-direction: column; min-width: 800px; + min-height: 0; padding: 15px 24px 10px; - background-color: colors.$white; overflow: auto; - min-height: 0; + background-color: colors.$white; @include mixins.displayFlex; diff --git a/src/lib/scss/fonts.scss b/src/lib/scss/fonts.scss index b5848f55..0416f5f0 100644 --- a/src/lib/scss/fonts.scss +++ b/src/lib/scss/fonts.scss @@ -1,8 +1,8 @@ /* roboto-300 - latin */ @font-face { - font-family: 'Roboto'; - font-style: normal; font-weight: 300; + font-family: Roboto; + font-style: normal; src: url('../fonts/roboto-v27-latin-300.eot'); /* IE9 Compat Modes */ src: local(''), @@ -15,9 +15,9 @@ /* roboto-regular - latin */ @font-face { - font-family: 'Roboto'; - font-style: normal; font-weight: 400; + font-family: Roboto; + font-style: normal; src: url('../fonts/roboto-v27-latin-regular.eot'); /* IE9 Compat Modes */ src: local(''), @@ -30,9 +30,9 @@ /* roboto-italic - latin */ @font-face { - font-family: 'Roboto'; - font-style: italic; font-weight: 400; + font-family: Roboto; + font-style: italic; src: url('../fonts/roboto-v27-latin-italic.eot'); /* IE9 Compat Modes */ src: local(''), @@ -45,9 +45,9 @@ /* roboto-500 - latin */ @font-face { - font-family: 'Roboto'; - font-style: normal; font-weight: 500; + font-family: Roboto; + font-style: normal; src: url('../fonts/roboto-v27-latin-500.eot'); /* IE9 Compat Modes */ src: local(''), @@ -60,9 +60,9 @@ /* roboto-500italic - latin */ @font-face { - font-family: 'Roboto'; - font-style: italic; font-weight: 500; + font-family: Roboto; + font-style: italic; src: url('../fonts/roboto-v27-latin-500italic.eot'); /* IE9 Compat Modes */ src: local(''), @@ -75,9 +75,9 @@ /* roboto-700 - latin */ @font-face { - font-family: 'Roboto'; - font-style: normal; font-weight: 700; + font-family: Roboto; + font-style: normal; src: url('../fonts/roboto-v27-latin-700.eot'); /* IE9 Compat Modes */ src: local(''), @@ -90,9 +90,9 @@ /* roboto-700italic - latin */ @font-face { - font-family: 'Roboto'; - font-style: italic; font-weight: 700; + font-family: Roboto; + font-style: italic; src: url('../fonts/roboto-v27-latin-700italic.eot'); /* IE9 Compat Modes */ src: local(''), @@ -105,9 +105,9 @@ /* source-code-pro-regular - latin */ @font-face { + font-weight: 400; font-family: 'Source Code Pro'; font-style: normal; - font-weight: 400; src: url('../fonts/source-code-pro-v14-latin-regular.eot'); /* IE9 Compat Modes */ src: local(''), diff --git a/src/lib/scss/shadows.scss b/src/lib/scss/shadows.scss index 37f904f3..d7cc32e6 100644 --- a/src/lib/scss/shadows.scss +++ b/src/lib/scss/shadows.scss @@ -9,7 +9,7 @@ $mainHeaderShadow: $filterShadow: 0 4px 8px rgba(colors.$black, 0.23); $tooltipShadow: 0 5px 11px rgba(colors.$black, 0.18); $hiddenChipsBlockShadow: 2px 2px 8px 2px rgba(colors.$black, 0.2); -$previewBoxShadowInit: 0px 3px 10px rgba(0, 0, 0, 0.07); +$previewBoxShadowInit: 0px 3px 10px rgb(0 0 0 / 7%); $previewBoxShadow: 0 2px 10px rgba(colors.$black, 0.2); $projectStatisticsShadow: 0 8px 30px rgba(colors.$topaz, 0.08); $dropdownShadow: 0 0 30px rgba(colors.$black, 0.15); From 8f0bdfa8b9795932c67dc25470636081400acc15 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Fri, 5 Sep 2025 15:56:03 +0300 Subject: [PATCH 03/10] return back sort --- src/lib/scss/common.scss | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/lib/scss/common.scss b/src/lib/scss/common.scss index b2310464..9469d985 100644 --- a/src/lib/scss/common.scss +++ b/src/lib/scss/common.scss @@ -1007,3 +1007,47 @@ a { opacity: 1; } } + +/* =========== SORT ============= */ + +.sortable-header { + &-cell { + position: relative; + border: 0; + border-radius: 0; + cursor: pointer; + + .sort-icon { + position: absolute; + top: auto; + right: 2px; + bottom: auto; + display: none; + } + + &_active { + background-color: colors.$alabaster; + + .sort-icon { + display: block; + } + } + + &:hover { + .sort-icon { + display: block; + } + } + + label { + cursor: pointer; + } + } + + &-label { + position: relative; + display: flex; + align-items: center; + padding-right: 25px; + } +} From 828728c9c2a81cd0a93e6aa2c811d2050c150920 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Fri, 5 Sep 2025 16:00:05 +0300 Subject: [PATCH 04/10] additional fix after rebase on dev --- src/lib/scss/common.scss | 2 ++ src/lib/scss/mixins.scss | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/scss/common.scss b/src/lib/scss/common.scss index 9469d985..3be8bb15 100644 --- a/src/lib/scss/common.scss +++ b/src/lib/scss/common.scss @@ -20,6 +20,8 @@ --mischkaColor: #{colors.$mischka}; } +/* =========== GENERAL ============= */ + #root { z-index: 1; display: flex; diff --git a/src/lib/scss/mixins.scss b/src/lib/scss/mixins.scss index 76ad6fd0..c425dfcf 100644 --- a/src/lib/scss/mixins.scss +++ b/src/lib/scss/mixins.scss @@ -8,7 +8,7 @@ left: 0; } -@mixin jobsFlex { +@mixin displayFlex { display: flex; flex-grow: 1; flex-shrink: 1; From c1fbb25fca6f8e4866af1a2f7bcb4ae529c113cd Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Thu, 2 Oct 2025 14:15:21 +0300 Subject: [PATCH 05/10] update dev deps that do not require node.js update and not related to react --- package.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 13952a29..ba37e090 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "react-transition-group": "*" }, "devDependencies": { - "@eslint/js": "^9.19.0", + "@eslint/js": "^9.36.0", "@reduxjs/toolkit": "^2.8.2", "@storybook/addon-actions": "^8.0.0", "@storybook/addon-essentials": "^8.0.0", @@ -71,20 +71,20 @@ "@types/react": "18.3.1", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "^4.3.4", - "classnames": "^2.3.1", - "cross-env": "^7.0.3", - "eslint": "^9.13.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.14", + "classnames": "^2.5.1", + "cross-env": "^10.1.0", + "eslint": "^9.36.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^6.1.0", + "eslint-plugin-react-refresh": "^0.4.23", "final-form": "^4.20.10", "final-form-arrays": "^3.1.0", - "globals": "^15.14.0", + "globals": "^16.4.0", "lodash": "^4.17.21", "moment": "^2.30.1", "node": "21.6.2", - "prettier": "3.3.3", + "prettier": "3.6.2", "prop-types": "^15.8.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -94,21 +94,21 @@ "react-redux": "^7.2.9", "react-router-dom": "6.22.3", "react-transition-group": "^4.4.5", - "sass": "^1.72.0", + "sass": "^1.93.2", "stylelint": "^16.21.0", "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^38.0.0", - "stylelint-config-standard-scss": "^15.0.1", + "stylelint-config-standard": "^39.0.0", + "stylelint-config-standard-scss": "^16.0.0", "stylelint-order": "^7.0.0", "stylelint-scss": "^6.12.1", - "tsup": "^8.3.6", - "typescript": "^5.7.3", - "typescript-eslint": "^8.23.0", - "vite": "^6.2.0", + "tsup": "^8.5.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^6.3.6", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-static-copy": "^2.2.0", - "vite-plugin-svgr": "^4.3.0" + "vite-plugin-static-copy": "^3.1.3", + "vite-plugin-svgr": "^4.5.0" }, "scripts": { "lint": "eslint 'src/**/*.{js,jsx}' --quiet", From a63a5094f7ab0d1855cea0144d8c9f95a160b5c8 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Fri, 3 Oct 2025 18:30:27 +0300 Subject: [PATCH 06/10] migrate and fix storybook --- .storybook/{main.js => main.mjs} | 35 ++- eslint.config.mjs | 4 +- package.json | 264 +++++++++--------- .../{Button.stories.js => Button.stories.jsx} | 2 +- .../{Chip.stories.js => Chip.stories.jsx} | 5 +- ...g.stories.js => ConfirmDialog.stories.jsx} | 0 ...ox.stories.js => FormCheckbox.stories.jsx} | 0 ...ox.stories.js => FormCombobox.stories.jsx} | 8 +- ...Input.stories.js => FormInput.stories.jsx} | 18 +- ...Radio.stories.js => FormRadio.stories.jsx} | 0 ...lect.stories.js => FormSelect.stories.jsx} | 0 ...ea.stories.js => FormTextarea.stories.jsx} | 0 ...tton.stories.js => LoadButton.stories.jsx} | 0 ...con.stories.js => RoundedIcon.stories.jsx} | 0 .../Tip/{Tip.stories.js => Tip.stories.jsx} | 0 ...Tooltip.stories.js => Tooltip.stories.jsx} | 2 +- 16 files changed, 177 insertions(+), 161 deletions(-) rename .storybook/{main.js => main.mjs} (62%) rename src/lib/components/Button/{Button.stories.js => Button.stories.jsx} (97%) rename src/lib/components/Chip/{Chip.stories.js => Chip.stories.jsx} (99%) rename src/lib/components/ConfirmDialog/{ConfirmDialog.stories.js => ConfirmDialog.stories.jsx} (100%) rename src/lib/components/FormCheckBox/{FormCheckbox.stories.js => FormCheckbox.stories.jsx} (100%) rename src/lib/components/FormCombobox/{FormCombobox.stories.js => FormCombobox.stories.jsx} (93%) rename src/lib/components/FormInput/{FormInput.stories.js => FormInput.stories.jsx} (87%) rename src/lib/components/FormRadio/{FormRadio.stories.js => FormRadio.stories.jsx} (100%) rename src/lib/components/FormSelect/{FormSelect.stories.js => FormSelect.stories.jsx} (100%) rename src/lib/components/FormTextarea/{FormTextarea.stories.js => FormTextarea.stories.jsx} (100%) rename src/lib/components/LoadButton/{LoadButton.stories.js => LoadButton.stories.jsx} (100%) rename src/lib/components/RoundedIcon/{RoundedIcon.stories.js => RoundedIcon.stories.jsx} (100%) rename src/lib/components/Tip/{Tip.stories.js => Tip.stories.jsx} (100%) rename src/lib/components/Tooltip/{Tooltip.stories.js => Tooltip.stories.jsx} (96%) diff --git a/.storybook/main.js b/.storybook/main.mjs similarity index 62% rename from .storybook/main.js rename to .storybook/main.mjs index 68ebfd4a..32668c2d 100644 --- a/.storybook/main.js +++ b/.storybook/main.mjs @@ -14,19 +14,30 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -module.exports = { - babel: async (options) => { - options.plugins.push('babel-plugin-inline-react-svg') - return options + +const config = { + framework: { + name: '@storybook/react-vite', + options: {} }, stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: [ - '@storybook/addon-links', - '@storybook/addon-essentials', - '@storybook/addon-interactions' - ], - framework: '@storybook/react', + addons: ['@storybook/addon-links', '@storybook/addon-docs'], core: { - builder: 'webpack5' - } + builder: '@storybook/builder-vite' + }, + // staticDirs: ['../src/lib/images'], + + // async viteFinal(viteConfig) { + // const { mergeConfig } = await import('vite'); + // const svgr = (await import('vite-plugin-svgr')).default; + + // return mergeConfig(viteConfig, { + // plugins: [ + // svgr({ include: '**/*.svg' }), // enables ?react imports + // ] + // }); + // } + } + +export default config diff --git a/eslint.config.mjs b/eslint.config.mjs index 5fbdd6a2..173c6fe4 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,6 +3,7 @@ import globals from 'globals' import js from '@eslint/js' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' +import storybook from 'eslint-plugin-storybook' export default [ { ignores: ['dist'] }, @@ -40,5 +41,6 @@ export default [ quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], semi: ['error', 'never'] } - } + }, + ...storybook.configs['flat/recommended'] ] diff --git a/package.json b/package.json index ba37e090..c84c492e 100644 --- a/package.json +++ b/package.json @@ -1,138 +1,136 @@ { - "name": "iguazio.dashboard-react-controls", - "version": "3.1.11", - "description": "Collection of resources (such as CSS styles, fonts and images) and ReactJS 17.x components to share among different Iguazio React repos.", - "module": "./dist/index.mjs", - "main": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "import": "./dist/index.mjs", - "types": "./dist/index.d.ts" - }, - "./components": { - "import": "./dist/components/index.mjs", - "types": "./dist/components/index.d.ts" - }, - "./elements": "./dist/elements/index.mjs", - "./hooks": "./dist/hooks/index.mjs", - "./constants": "./dist/constants.mjs", - "./types": "./dist/types.mjs", - "./utils": "./dist/utils/index.mjs", - "./utils/*": "./dist/utils/*", - "./reducers": "./dist/reducers/index.mjs", - "./reducers/*": "./dist/reducers/*", - "./images/*": "./dist/images/*", - "./scss/*": "./dist/scss/*", - "./index.css": "./dist/index.css" + "name": "iguazio.dashboard-react-controls", + "version": "3.1.11", + "description": "Collection of resources (such as CSS styles, fonts and images) and ReactJS 17.x components to share among different Iguazio React repos.", + "module": "./dist/index.mjs", + "main": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" }, - "files": [ - "dist", - "README.md" - ], - "repository": { - "type": "git", - "url": "git@github.com:iguazio/dashboard-react-controls.git" + "./components": { + "import": "./dist/components/index.mjs", + "types": "./dist/components/index.d.ts" }, - "keywords": [ - "Iguazio", - "iguazio", - "MLRun", - "mlrun" + "./elements": "./dist/elements/index.mjs", + "./hooks": "./dist/hooks/index.mjs", + "./constants": "./dist/constants.mjs", + "./types": "./dist/types.mjs", + "./utils": "./dist/utils/index.mjs", + "./utils/*": "./dist/utils/*", + "./reducers": "./dist/reducers/index.mjs", + "./reducers/*": "./dist/reducers/*", + "./images/*": "./dist/images/*", + "./scss/*": "./dist/scss/*", + "./index.css": "./dist/index.css" + }, + "files": [ + "dist", + "README.md" + ], + "repository": { + "type": "git", + "url": "git@github.com:iguazio/dashboard-react-controls.git" + }, + "keywords": [ + "Iguazio", + "iguazio", + "MLRun", + "mlrun" + ], + "peerDependencies": { + "@reduxjs/toolkit": "*", + "classnames": "*", + "final-form": "*", + "final-form-arrays": "*", + "lodash": "*", + "moment": "*", + "prop-types": "*", + "react": "*", + "react-dom": "*", + "react-final-form": "*", + "react-final-form-arrays": "*", + "react-modal-promise": "*", + "react-redux": "*", + "react-router-dom": "*", + "react-transition-group": "*" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@reduxjs/toolkit": "^2.8.2", + "@storybook/addon-docs": "9.1.10", + "@storybook/addon-links": "^9.1.10", + "@storybook/builder-vite": "^9.1.10", + "@storybook/react-vite": "^9.1.10", + "@storybook/testing-library": "0.2.2", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "classnames": "^2.5.1", + "cross-env": "^10.1.0", + "eslint": "^9.36.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^6.1.0", + "eslint-plugin-react-refresh": "^0.4.23", + "eslint-plugin-storybook": "9.1.10", + "final-form": "^4.20.10", + "final-form-arrays": "^3.1.0", + "globals": "^16.4.0", + "lodash": "^4.17.21", + "moment": "^2.30.1", + "node": "21.6.2", + "prettier": "3.6.2", + "prop-types": "^15.8.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-final-form": "^6.5.9", + "react-final-form-arrays": "^3.1.4", + "react-modal-promise": "^1.0.2", + "react-redux": "^7.2.9", + "react-router-dom": "6.22.3", + "react-transition-group": "^4.4.5", + "sass": "^1.93.2", + "stylelint": "^16.21.0", + "stylelint-config-rational-order": "^0.1.2", + "stylelint-config-standard": "^39.0.0", + "stylelint-config-standard-scss": "^16.0.0", + "stylelint-order": "^7.0.0", + "stylelint-scss": "^6.12.1", + "tsup": "^8.5.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^6.3.6", + "vite-plugin-commonjs": "^0.10.4", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-static-copy": "^3.1.3", + "vite-plugin-svgr": "^4.5.0" + }, + "scripts": { + "lint": "eslint 'src/**/*.{js,jsx}' --quiet", + "lint:fix": "eslint 'src/**/*.{js,jsx}' --fix", + "stylelint": "stylelint 'src/**/*.{css,scss}'", + "prettier": "prettier --check 'src/**/*.{js,jsx,scss}'", + "prettier:fix": "prettier --write 'src/**/*.{js,jsx,scss}'", + "build-storybook": "build-storybook", + "storybook": "storybook dev -p 6006", + "start": "vite", + "build": "vite build && npx tsc", + "compile": "cross-env NODE_ENV=development vite build && npx tsc", + "serve": "vite preview" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" ], - "peerDependencies": { - "@reduxjs/toolkit": "*", - "classnames": "*", - "final-form": "*", - "final-form-arrays": "*", - "lodash": "*", - "moment": "*", - "prop-types": "*", - "react": "*", - "react-dom": "*", - "react-final-form": "*", - "react-final-form-arrays": "*", - "react-modal-promise": "*", - "react-redux": "*", - "react-router-dom": "*", - "react-transition-group": "*" - }, - "devDependencies": { - "@eslint/js": "^9.36.0", - "@reduxjs/toolkit": "^2.8.2", - "@storybook/addon-actions": "^8.0.0", - "@storybook/addon-essentials": "^8.0.0", - "@storybook/addon-interactions": "^8.0.0", - "@storybook/addon-links": "^8.0.0", - "@storybook/builder-webpack5": "^8.0.0", - "@storybook/manager-webpack5": "^6.5.16", - "@storybook/react": "^8.0.0", - "@storybook/testing-library": "0.2.2", - "@types/react": "18.3.1", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "classnames": "^2.5.1", - "cross-env": "^10.1.0", - "eslint": "^9.36.0", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^6.1.0", - "eslint-plugin-react-refresh": "^0.4.23", - "final-form": "^4.20.10", - "final-form-arrays": "^3.1.0", - "globals": "^16.4.0", - "lodash": "^4.17.21", - "moment": "^2.30.1", - "node": "21.6.2", - "prettier": "3.6.2", - "prop-types": "^15.8.1", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-final-form": "^6.5.9", - "react-final-form-arrays": "^3.1.4", - "react-modal-promise": "^1.0.2", - "react-redux": "^7.2.9", - "react-router-dom": "6.22.3", - "react-transition-group": "^4.4.5", - "sass": "^1.93.2", - "stylelint": "^16.21.0", - "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^39.0.0", - "stylelint-config-standard-scss": "^16.0.0", - "stylelint-order": "^7.0.0", - "stylelint-scss": "^6.12.1", - "tsup": "^8.5.0", - "typescript": "^5.9.3", - "typescript-eslint": "^8.45.0", - "vite": "^6.3.6", - "vite-plugin-commonjs": "^0.10.4", - "vite-plugin-eslint": "^1.8.1", - "vite-plugin-static-copy": "^3.1.3", - "vite-plugin-svgr": "^4.5.0" - }, - "scripts": { - "lint": "eslint 'src/**/*.{js,jsx}' --quiet", - "lint:fix": "eslint 'src/**/*.{js,jsx}' --fix", - "stylelint": "stylelint 'src/**/*.{css,scss}'", - "prettier": "prettier --check 'src/**/*.{js,jsx,scss}'", - "prettier:fix": "prettier --write 'src/**/*.{js,jsx,scss}'", - "build-storybook": "build-storybook", - "storybook": "start-storybook -p 6006", - "start": "vite", - "build": "vite build && npx tsc", - "compile": "cross-env NODE_ENV=development vite build && npx tsc", - "serve": "vite preview" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } } diff --git a/src/lib/components/Button/Button.stories.js b/src/lib/components/Button/Button.stories.jsx similarity index 97% rename from src/lib/components/Button/Button.stories.js rename to src/lib/components/Button/Button.stories.jsx index 791bd895..adeda442 100644 --- a/src/lib/components/Button/Button.stories.js +++ b/src/lib/components/Button/Button.stories.jsx @@ -26,7 +26,7 @@ import { TERTIARY_BUTTON } from '../../constants' -import EyeIcon from '../../images/eye.svg?react' +import EyeIcon from '../../images/eye-icon.svg?react' import CaretIcon from '../../images/dropdown.svg?react' export default { diff --git a/src/lib/components/Chip/Chip.stories.js b/src/lib/components/Chip/Chip.stories.jsx similarity index 99% rename from src/lib/components/Chip/Chip.stories.js rename to src/lib/components/Chip/Chip.stories.jsx index f28e0c1c..e3d7c4d7 100644 --- a/src/lib/components/Chip/Chip.stories.js +++ b/src/lib/components/Chip/Chip.stories.jsx @@ -34,8 +34,9 @@ const commonArgs = { borderRadius: 'primary', borderColor: 'transparent', density: 'dense', - font: 'purple' - } + font: 'purple', + }, + ref: {} } const Template = args => diff --git a/src/lib/components/ConfirmDialog/ConfirmDialog.stories.js b/src/lib/components/ConfirmDialog/ConfirmDialog.stories.jsx similarity index 100% rename from src/lib/components/ConfirmDialog/ConfirmDialog.stories.js rename to src/lib/components/ConfirmDialog/ConfirmDialog.stories.jsx diff --git a/src/lib/components/FormCheckBox/FormCheckbox.stories.js b/src/lib/components/FormCheckBox/FormCheckbox.stories.jsx similarity index 100% rename from src/lib/components/FormCheckBox/FormCheckbox.stories.js rename to src/lib/components/FormCheckBox/FormCheckbox.stories.jsx diff --git a/src/lib/components/FormCombobox/FormCombobox.stories.js b/src/lib/components/FormCombobox/FormCombobox.stories.jsx similarity index 93% rename from src/lib/components/FormCombobox/FormCombobox.stories.js rename to src/lib/components/FormCombobox/FormCombobox.stories.jsx index d278a0df..2f10e067 100644 --- a/src/lib/components/FormCombobox/FormCombobox.stories.js +++ b/src/lib/components/FormCombobox/FormCombobox.stories.jsx @@ -66,8 +66,8 @@ Chunky.args = { density: 'chunky' } -export const withDefaultValue = Template.bind({}) -withDefaultValue.args = { +export const WithDefaultValue = Template.bind({}) +WithDefaultValue.args = { ...commonArgs, selectDefaultValue: { className: 'path-type-store', @@ -77,8 +77,8 @@ withDefaultValue.args = { inputDefaultValue: 'artifacts/default' } -export const withSuggestions = Template.bind({}) -withSuggestions.args = { +export const WithSuggestions = Template.bind({}) +WithSuggestions.args = { ...commonArgs, suggestionList: [ { diff --git a/src/lib/components/FormInput/FormInput.stories.js b/src/lib/components/FormInput/FormInput.stories.jsx similarity index 87% rename from src/lib/components/FormInput/FormInput.stories.js rename to src/lib/components/FormInput/FormInput.stories.jsx index 62cbb5b0..7ab3f9fb 100644 --- a/src/lib/components/FormInput/FormInput.stories.js +++ b/src/lib/components/FormInput/FormInput.stories.jsx @@ -19,10 +19,14 @@ import { Form } from 'react-final-form' import FormInput from '/src/lib/components/FormInput/FormInput' import { getValidationRules } from '/src/lib/utils/validation.util' +import { fn } from 'storybook/test' export default { title: 'Example/FormInput', - component: FormInput + component: FormInput, + args: { + onValidationError: fn() + } } const commonArgs = { @@ -59,15 +63,15 @@ Chunky.args = { label: 'Chunky' } -export const withTip = Template.bind({}) -withTip.args = { +export const WithTip = Template.bind({}) +WithTip.args = { ...commonArgs, label: 'With Tip', tip: 'Tip' } -export const withValidationRules = Template.bind({}) -withValidationRules.args = { +export const WithValidationRules = Template.bind({}) +WithValidationRules.args = { ...commonArgs, density: 'chunky', label: 'With validation rules', @@ -75,8 +79,8 @@ withValidationRules.args = { validationRules: getValidationRules('common.name') } -export const withLink = Template.bind({}) -withLink.args = { +export const WithLink = Template.bind({}) +WithLink.args = { ...commonArgs, label: 'label with static link', link: { diff --git a/src/lib/components/FormRadio/FormRadio.stories.js b/src/lib/components/FormRadio/FormRadio.stories.jsx similarity index 100% rename from src/lib/components/FormRadio/FormRadio.stories.js rename to src/lib/components/FormRadio/FormRadio.stories.jsx diff --git a/src/lib/components/FormSelect/FormSelect.stories.js b/src/lib/components/FormSelect/FormSelect.stories.jsx similarity index 100% rename from src/lib/components/FormSelect/FormSelect.stories.js rename to src/lib/components/FormSelect/FormSelect.stories.jsx diff --git a/src/lib/components/FormTextarea/FormTextarea.stories.js b/src/lib/components/FormTextarea/FormTextarea.stories.jsx similarity index 100% rename from src/lib/components/FormTextarea/FormTextarea.stories.js rename to src/lib/components/FormTextarea/FormTextarea.stories.jsx diff --git a/src/lib/components/LoadButton/LoadButton.stories.js b/src/lib/components/LoadButton/LoadButton.stories.jsx similarity index 100% rename from src/lib/components/LoadButton/LoadButton.stories.js rename to src/lib/components/LoadButton/LoadButton.stories.jsx diff --git a/src/lib/components/RoundedIcon/RoundedIcon.stories.js b/src/lib/components/RoundedIcon/RoundedIcon.stories.jsx similarity index 100% rename from src/lib/components/RoundedIcon/RoundedIcon.stories.js rename to src/lib/components/RoundedIcon/RoundedIcon.stories.jsx diff --git a/src/lib/components/Tip/Tip.stories.js b/src/lib/components/Tip/Tip.stories.jsx similarity index 100% rename from src/lib/components/Tip/Tip.stories.js rename to src/lib/components/Tip/Tip.stories.jsx diff --git a/src/lib/components/Tooltip/Tooltip.stories.js b/src/lib/components/Tooltip/Tooltip.stories.jsx similarity index 96% rename from src/lib/components/Tooltip/Tooltip.stories.js rename to src/lib/components/Tooltip/Tooltip.stories.jsx index 13dfe61b..d9c4c780 100644 --- a/src/lib/components/Tooltip/Tooltip.stories.js +++ b/src/lib/components/Tooltip/Tooltip.stories.jsx @@ -18,7 +18,7 @@ import React from 'react' import Tooltip from '/src/lib/components/Tooltip/Tooltip' import TextTooltipTemplate from '/src/lib/components/TooltipTemplate/TextTooltipTemplate' -import EyeIcon from '../../images/eye.svg?react' +import EyeIcon from '../../images/eye-icon.svg?react' export default { title: 'Example/Tooltip', From 74e75f45a858fa1c67ebf52a282dae78856cfac0 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Mon, 6 Oct 2025 13:18:53 +0300 Subject: [PATCH 07/10] remove commented code --- .storybook/main.mjs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.storybook/main.mjs b/.storybook/main.mjs index 32668c2d..5f111ded 100644 --- a/.storybook/main.mjs +++ b/.storybook/main.mjs @@ -24,20 +24,7 @@ const config = { addons: ['@storybook/addon-links', '@storybook/addon-docs'], core: { builder: '@storybook/builder-vite' - }, - // staticDirs: ['../src/lib/images'], - - // async viteFinal(viteConfig) { - // const { mergeConfig } = await import('vite'); - // const svgr = (await import('vite-plugin-svgr')).default; - - // return mergeConfig(viteConfig, { - // plugins: [ - // svgr({ include: '**/*.svg' }), // enables ?react imports - // ] - // }); - // } - + } } export default config From 0c8656a75d459e9b84a6694362506bb04297e015 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Tue, 7 Oct 2025 14:14:55 +0300 Subject: [PATCH 08/10] removed strorybook testing lib --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c84c492e..d691f928 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,6 @@ "@storybook/addon-links": "^9.1.10", "@storybook/builder-vite": "^9.1.10", "@storybook/react-vite": "^9.1.10", - "@storybook/testing-library": "0.2.2", "@types/react": "18.3.1", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "^4.3.4", From 4716007d287e25ac7512764054c768fc19e40065 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Tue, 7 Oct 2025 14:26:22 +0300 Subject: [PATCH 09/10] prettier fix --- src/lib/components/Chip/Chip.stories.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/Chip/Chip.stories.jsx b/src/lib/components/Chip/Chip.stories.jsx index e3d7c4d7..8f7dda24 100644 --- a/src/lib/components/Chip/Chip.stories.jsx +++ b/src/lib/components/Chip/Chip.stories.jsx @@ -34,7 +34,7 @@ const commonArgs = { borderRadius: 'primary', borderColor: 'transparent', density: 'dense', - font: 'purple', + font: 'purple' }, ref: {} } From 0a472e9a2cfd8b9f6b1ab04825e0353c3a76f97c Mon Sep 17 00:00:00 2001 From: mariana-furyk Date: Fri, 28 Nov 2025 00:43:28 +0200 Subject: [PATCH 10/10] Impl [Infra] Update MLrun UI React 18 to 19 --- eslint.config.mjs | 4 +- package.json | 8 +- .../components/ActionsMenu/ActionsMenu.jsx | 22 ++--- src/lib/components/Button/Button.jsx | 31 +++--- src/lib/components/Chip/Chip.jsx | 52 +++++----- .../HiddenChipsBlock/HiddenChipsBlock.jsx | 33 +++---- src/lib/components/ChipForm/ChipForm.jsx | 39 ++++---- .../FormChipCell/FormChip/FormChip.jsx | 57 ++++++----- .../FormChipCell/FormChipCellView.jsx | 64 ++++++------- .../HiddenChipsBlock/HiddenChipsBlock.jsx | 17 ++-- .../FormChipCell/NewChipForm/NewChipForm.jsx | 96 +++++++++---------- .../NewChipInput/NewChipInput.jsx | 9 +- .../components/FormCombobox/FormCombobox.jsx | 34 +++---- src/lib/components/FormInput/FormInput.jsx | 67 +++++++------ .../components/FormOnChange/FormOnChange.jsx | 2 +- src/lib/components/FormSelect/FormSelect.jsx | 27 ++++-- .../components/FormTextarea/FormTextarea.jsx | 60 +++++------- src/lib/components/LoadButton/LoadButton.jsx | 14 +-- .../components/PopUpDialog/PopUpDialog.jsx | 33 +++---- .../components/RoundedIcon/RoundedIcon.jsx | 4 +- src/lib/components/TabsSlider/TabsSlider.jsx | 12 ++- src/lib/components/Tip/Tip.jsx | 2 +- src/lib/components/Wizard/Wizard.jsx | 24 ++--- .../FormActionButton/FormActionButton.jsx | 27 +++--- src/lib/elements/OptionsMenu/OptionsMenu.jsx | 11 +-- src/lib/elements/TableHead/TableHead.jsx | 17 ++-- src/lib/hooks/useChipCell.hook.js | 2 +- src/lib/hooks/useDetails.hook.jsx | 38 ++++---- src/lib/hooks/useHiddenChipsBlock.hook.js | 6 +- 29 files changed, 391 insertions(+), 421 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 173c6fe4..5fbdd6a2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,7 +3,6 @@ import globals from 'globals' import js from '@eslint/js' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' -import storybook from 'eslint-plugin-storybook' export default [ { ignores: ['dist'] }, @@ -41,6 +40,5 @@ export default [ quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], semi: ['error', 'never'] } - }, - ...storybook.configs['flat/recommended'] + } ] diff --git a/package.json b/package.json index d691f928..8011ea3c 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "eslint": "^9.36.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^6.1.0", + "eslint-plugin-react-hooks": "^7.0.0", "eslint-plugin-react-refresh": "^0.4.23", "eslint-plugin-storybook": "9.1.10", "final-form": "^4.20.10", @@ -83,13 +83,13 @@ "node": "21.6.2", "prettier": "3.6.2", "prop-types": "^15.8.1", - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-modal-promise": "^1.0.2", "react-redux": "^7.2.9", - "react-router-dom": "6.22.3", + "react-router-dom": "7.9.4", "react-transition-group": "^4.4.5", "sass": "^1.93.2", "stylelint": "^16.21.0", diff --git a/src/lib/components/ActionsMenu/ActionsMenu.jsx b/src/lib/components/ActionsMenu/ActionsMenu.jsx index 6a4d80c9..9a3620be 100644 --- a/src/lib/components/ActionsMenu/ActionsMenu.jsx +++ b/src/lib/components/ActionsMenu/ActionsMenu.jsx @@ -19,7 +19,6 @@ such restriction. */ import React, { useCallback, useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' -import { isEmpty } from 'lodash' import classnames from 'classnames' import ActionsMenuItem from '../../elements/ActionsMenuItem/ActionsMenuItem' @@ -39,15 +38,16 @@ const ActionsMenu = ({ time = 100, withQuickActions = false }) => { - const [[actionMenu, quickActions], setActionMenuContent] = useState(menu) - const [isIconDisplayed, setIsIconDisplayed] = useState(false) + const [actionMenu, quickActions] = + typeof menu === 'function' ? menu(dataItem, menuPosition) : menu + const isIconDisplayed = Boolean(actionMenu?.some(menuItem => menuItem.icon)) const [isShowMenu, setIsShowMenu] = useState(false) const actionMenuRef = useRef() const actionMenuBtnRef = useRef() const dropDownMenuRef = useRef() const mainActionsWrapperRef = useRef() - let idTimeout = null + const idTimeoutRef = useRef(null) const actionMenuClassNames = classnames( 'actions-menu__container', @@ -77,7 +77,7 @@ const ActionsMenu = ({ const onMouseOut = () => { if (isShowMenu) { - idTimeout = setTimeout(() => { + idTimeoutRef.current = setTimeout(() => { setIsShowMenu(false) }, time) } @@ -88,19 +88,9 @@ const ActionsMenu = ({ setIsShowMenu(false) } - if (idTimeout) clearTimeout(idTimeout) + if (idTimeoutRef.current) clearTimeout(idTimeoutRef.current) } - useEffect(() => { - if (!isEmpty(dataItem)) { - setActionMenuContent(typeof menu === 'function' ? menu(dataItem, menuPosition) : menu) - } - }, [dataItem, menu, menuPosition]) - - useEffect(() => { - setIsIconDisplayed(actionMenu?.some(menuItem => menuItem.icon)) - }, [actionMenu]) - useEffect(() => { window.addEventListener('click', clickHandler) window.addEventListener('scroll', scrollHandler, true) diff --git a/src/lib/components/Button/Button.jsx b/src/lib/components/Button/Button.jsx index 542eda8a..9f1999a7 100644 --- a/src/lib/components/Button/Button.jsx +++ b/src/lib/components/Button/Button.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' @@ -26,20 +26,18 @@ import { TERTIARY_BUTTON } from '../../constants' import './Button.scss' -let Button = ( - { - className = '', - density = 'normal', - icon = null, - iconPosition = 'left', - id = 'btn', - label = 'Button', - tooltip = '', - variant = TERTIARY_BUTTON, - ...restProps - }, - ref -) => { +const Button = ({ + className = '', + density = 'normal', + icon = null, + iconPosition = 'left', + id = 'btn', + label = 'Button', + ref, + tooltip = '', + variant = TERTIARY_BUTTON, + ...restProps +}) => { const buttonClassName = classNames('btn', `btn-${variant}`, `btn-${density}`, className) return ( @@ -55,8 +53,6 @@ let Button = ( ) } -Button = forwardRef(Button) - Button.displayName = 'Button' Button.propTypes = { @@ -66,6 +62,7 @@ Button.propTypes = { iconPosition: PropTypes.oneOf(['left', 'right']), id: PropTypes.string, label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), + ref: PropTypes.object.isRequired, tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), variant: BUTTON_VARIANTS } diff --git a/src/lib/components/Chip/Chip.jsx b/src/lib/components/Chip/Chip.jsx index b44a225b..a14a7175 100644 --- a/src/lib/components/Chip/Chip.jsx +++ b/src/lib/components/Chip/Chip.jsx @@ -32,29 +32,28 @@ import Close from '../../images/close.svg?react' import './chip.scss' -let Chip = ( - { - chip, - chipIndex = null, - chipOptions, - className, - editConfig = {}, - handleEditChip = () => {}, - handleIsEdit = () => {}, - handleRemoveChip = () => {}, - hiddenChips = false, - isDeleteMode = false, - isEditMode = false, - onClick = null, - setChipsSizes = () => {}, - setEditConfig = () => {}, - setValidation = null, - shortChip = false, - showChips, - textOverflowEllipsis = false - }, - { chipsCellRef, hiddenChipsCounterRef } -) => { +let Chip = ({ + chip, + chipIndex = null, + chipOptions, + className, + editConfig = {}, + handleEditChip = () => {}, + handleIsEdit = () => {}, + handleRemoveChip = () => {}, + hiddenChips = false, + isDeleteMode = false, + isEditMode = false, + onClick = null, + ref, + setChipsSizes = () => {}, + setEditConfig = () => {}, + setValidation = null, + shortChip = false, + showChips, + textOverflowEllipsis = false +}) => { + const { chipsCellRef, hiddenChipsCounterRef } = ref const [validationRules, setValidationRules] = useState([]) const frontendSpec = useSelector(store => store.appStore?.frontendSpec) ?? {} const chipRef = React.useRef() @@ -105,7 +104,9 @@ let Chip = ( useEffect(() => { if (setValidation) { - checkValidation(chip.value.match(/^(?|.+?):\s?(?|.+?)$/)?.groups?.key) + queueMicrotask(() => { + checkValidation(chip.value.match(/^(?|.+?):\s?(?|.+?)$/)?.groups?.key) + }) } }, [checkValidation, chip, setValidation]) @@ -170,8 +171,6 @@ let Chip = ( ) } -Chip = React.forwardRef(Chip) - Chip.displayName = 'Chip' Chip.propTypes = { @@ -187,6 +186,7 @@ Chip.propTypes = { isDeleteMode: PropTypes.bool, isEditMode: PropTypes.bool, onClick: PropTypes.func, + ref: PropTypes.object.isRequired, setChipsSizes: PropTypes.func, setEditConfig: PropTypes.func, setValidation: PropTypes.func, diff --git a/src/lib/components/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx b/src/lib/components/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx index 0567d826..59ea4314 100644 --- a/src/lib/components/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx +++ b/src/lib/components/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx @@ -27,22 +27,21 @@ import ChipTooltip from '../ChipTooltip/ChipTooltip' import { CHIP_OPTIONS, CHIPS } from '../../../types' import { useHiddenChipsBlock } from '../../../hooks' -let HiddenChipsBlock = ( - { - chips = [], - chipIndex = 0, - chipOptions, - className, - editConfig = {}, - handleEditChip, - handleIsEdit = () => {}, - handleRemoveChip, - handleShowElements, - isEditMode = false, - setEditConfig = () => {} - }, - { hiddenChipsCounterRef, hiddenChipsPopUpRef } -) => { +let HiddenChipsBlock = ({ + chips = [], + chipIndex = 0, + chipOptions, + className, + editConfig = {}, + handleEditChip, + handleIsEdit = () => {}, + handleRemoveChip, + handleShowElements, + isEditMode = false, + ref, + setEditConfig = () => {} +}) => { + const { hiddenChipsCounterRef, hiddenChipsPopUpRef } = ref const { hiddenChipsBlockClassNames } = useHiddenChipsBlock( hiddenChipsCounterRef, hiddenChipsPopUpRef @@ -85,8 +84,6 @@ let HiddenChipsBlock = ( ) } -HiddenChipsBlock = React.forwardRef(HiddenChipsBlock) - HiddenChipsBlock.displayName = 'HiddenChipsBlock' HiddenChipsBlock.propTypes = { diff --git a/src/lib/components/ChipForm/ChipForm.jsx b/src/lib/components/ChipForm/ChipForm.jsx index 91732304..c29a14c9 100644 --- a/src/lib/components/ChipForm/ChipForm.jsx +++ b/src/lib/components/ChipForm/ChipForm.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useState, useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react' +import React, { useState, useCallback, useEffect, useLayoutEffect, useRef } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { isEmpty } from 'lodash' @@ -30,27 +30,23 @@ import { CHIP_OPTIONS } from '../../types' import './chipForm.scss' -let ChipForm = ( - { - checkValidation = null, - chipOptions, - className = '', - editConfig, - onChange, - setEditConfig, - validationRules = [], - value - }, - ref -) => { +let ChipForm = ({ + checkValidation = null, + chipOptions, + className = '', + editConfig, + onChange, + ref, + setEditConfig, + validationRules = [], + value +}) => { const [chip, setChip] = useState({ ...value, keyFieldWidth: 0, valueFieldWidth: 0 }) - const maxWidthInput = useMemo(() => { - return ref.current?.clientWidth - 50 - }, [ref]) + const [maxWidthInput, setMaxWidthInput] = useState(0) const { background, borderColor, density, font, borderRadius } = chipOptions const minWidthInput = 25 const minWidthValueInput = 35 @@ -78,6 +74,12 @@ let ChipForm = ( !editConfig.isValueFocused && 'item_edited' ) + useLayoutEffect(() => { + if (ref.current) { + setMaxWidthInput(ref.current.clientWidth - 50) + } + }, [ref]) + useLayoutEffect(() => { if (!chip.keyFieldWidth && !chip.valueFieldWidth) { const currentWidthKeyInput = refInputKey.current.scrollWidth + 1 @@ -273,8 +275,6 @@ let ChipForm = ( ) } -ChipForm = React.forwardRef(ChipForm) - ChipForm.displayName = 'ChipForm' ChipForm.propTypes = { @@ -283,6 +283,7 @@ ChipForm.propTypes = { className: PropTypes.string, editConfig: PropTypes.object.isRequired, onChange: PropTypes.func.isRequired, + ref: PropTypes.object.isRequired, setEditConfig: PropTypes.func.isRequired, validationRules: PropTypes.array, value: PropTypes.object.isRequired diff --git a/src/lib/components/FormChipCell/FormChip/FormChip.jsx b/src/lib/components/FormChipCell/FormChip/FormChip.jsx index 9609471a..f8d4e1c6 100644 --- a/src/lib/components/FormChipCell/FormChip/FormChip.jsx +++ b/src/lib/components/FormChipCell/FormChip/FormChip.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useLayoutEffect, forwardRef } from 'react' +import React, { useLayoutEffect } from 'react' import PropTypes from 'prop-types' import NewChipForm from '../NewChipForm/NewChipForm' @@ -23,34 +23,32 @@ import { CHIP_OPTIONS } from '../../../types' import './formChip.scss' -let FormChip = ( - { - chip, - chipIndex, - chipSizeIsRecalculated, - setChipSizeIsRecalculated, - chipOptions = { - background: 'purple', - boldValue: false, - borderRadius: 'primary', - borderColor: 'transparent', - density: 'dense', - font: 'purple' - }, - editConfig, - handleEditChip, - handleRemoveChip, - handleToEditMode, - isEditable = false, - keyName = '', - meta, - setChipsSizes, - setEditConfig, - validationRules = {}, - valueName = '' +let FormChip = ({ + chip, + chipIndex, + chipSizeIsRecalculated, + setChipSizeIsRecalculated, + chipOptions = { + background: 'purple', + boldValue: false, + borderRadius: 'primary', + borderColor: 'transparent', + density: 'dense', + font: 'purple' }, - ref -) => { + editConfig, + handleEditChip, + handleRemoveChip, + handleToEditMode, + isEditable = false, + keyName = '', + meta, + ref, + setChipsSizes, + setEditConfig, + validationRules = {}, + valueName = '' +}) => { const chipRef = React.useRef() useLayoutEffect(() => { if (chipRef.current && setChipsSizes && chipSizeIsRecalculated) { @@ -84,8 +82,6 @@ let FormChip = ( ) } -FormChip = forwardRef(FormChip) - FormChip.displayName = 'FormChip' FormChip.propTypes = { @@ -101,6 +97,7 @@ FormChip.propTypes = { isEditable: PropTypes.bool, keyName: PropTypes.string, meta: PropTypes.object.isRequired, + ref: PropTypes.object.isRequired, setChipsSizes: PropTypes.func.isRequired, setEditConfig: PropTypes.func.isRequired, validationRules: PropTypes.object, diff --git a/src/lib/components/FormChipCell/FormChipCellView.jsx b/src/lib/components/FormChipCell/FormChipCellView.jsx index 810f191c..c5cec8a5 100644 --- a/src/lib/components/FormChipCell/FormChipCellView.jsx +++ b/src/lib/components/FormChipCell/FormChipCellView.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { FieldArray } from 'react-final-form-arrays' @@ -31,37 +31,36 @@ import { uniquenessError } from './formChipCell.util' import Add from '../../images/add.svg?react' -let FormChipCellView = ( - { - chipOptions = { - background: 'purple', - boldValue: false, - borderRadius: 'primary', - borderColor: 'transparent', - density: 'dense', - font: 'purple' - }, - chipSizeIsRecalculated, - setChipSizeIsRecalculated, - chips, - editConfig, - handleAddNewChip, - handleEditChip, - handleRemoveChip, - handleShowElements, - handleToEditMode, - isEditable = false, - name, - setChipsSizes, - setEditConfig, - shortChips = false, - showChips, - showHiddenChips, - validateFields, - validationRules = {} +let FormChipCellView = ({ + chipOptions = { + background: 'purple', + boldValue: false, + borderRadius: 'primary', + borderColor: 'transparent', + density: 'dense', + font: 'purple' }, - { chipsCellRef, chipsWrapperRef, hiddenChipsCounterRef, hiddenChipsPopUpRef } -) => { + chipSizeIsRecalculated, + setChipSizeIsRecalculated, + chips, + editConfig, + handleAddNewChip, + handleEditChip, + handleRemoveChip, + handleShowElements, + handleToEditMode, + isEditable = false, + name, + ref, + setChipsSizes, + setEditConfig, + shortChips = false, + showChips, + showHiddenChips, + validateFields, + validationRules = {} +}) => { + const { chipsCellRef, chipsWrapperRef, hiddenChipsCounterRef, hiddenChipsPopUpRef } = ref const buttonAddClassNames = classnames( 'button-add', chipOptions.background && `button-add-background_${chipOptions.background}`, @@ -206,8 +205,6 @@ let FormChipCellView = ( ) } -FormChipCellView = forwardRef(FormChipCellView) - FormChipCellView.displayName = 'FormChipCellView' FormChipCellView.propTypes = { @@ -224,6 +221,7 @@ FormChipCellView.propTypes = { handleToEditMode: PropTypes.func.isRequired, isEditable: PropTypes.bool, name: PropTypes.string.isRequired, + ref: PropTypes.object.isRequired, setChipsSizes: PropTypes.func.isRequired, setEditConfig: PropTypes.func.isRequired, shortChips: PropTypes.bool, diff --git a/src/lib/components/FormChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx b/src/lib/components/FormChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx index cf1f3ead..070ab271 100644 --- a/src/lib/components/FormChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx +++ b/src/lib/components/FormChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef, useEffect } from 'react' +import React, { useEffect } from 'react' import { createPortal } from 'react-dom' import PropTypes from 'prop-types' import classnames from 'classnames' @@ -25,10 +25,15 @@ import TextTooltipTemplate from '../../TooltipTemplate/TextTooltipTemplate' import { CHIP_OPTIONS } from '../../../types' import { useHiddenChipsBlock } from '../../../hooks' -let HiddenChipsBlock = ( - { chipClassNames, chipOptions, chips, handleShowElements, textOverflowEllipsis = false }, - { hiddenChipsCounterRef, hiddenChipsPopUpRef } -) => { +let HiddenChipsBlock = ({ + chipClassNames, + chipOptions, + chips, + handleShowElements, + ref, + textOverflowEllipsis = false +}) => { + const { hiddenChipsCounterRef, hiddenChipsPopUpRef } = ref const { hiddenChipsBlockClassNames } = useHiddenChipsBlock( hiddenChipsCounterRef, hiddenChipsPopUpRef @@ -102,8 +107,6 @@ let HiddenChipsBlock = ( ) } -HiddenChipsBlock = forwardRef(HiddenChipsBlock) - HiddenChipsBlock.displayName = 'HiddenChipsBlock' HiddenChipsBlock.propTypes = { diff --git a/src/lib/components/FormChipCell/NewChipForm/NewChipForm.jsx b/src/lib/components/FormChipCell/NewChipForm/NewChipForm.jsx index 858ab06a..8dc26a8d 100644 --- a/src/lib/components/FormChipCell/NewChipForm/NewChipForm.jsx +++ b/src/lib/components/FormChipCell/NewChipForm/NewChipForm.jsx @@ -14,14 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { - useState, - useCallback, - useEffect, - useLayoutEffect, - useMemo, - forwardRef -} from 'react' +import React, { useState, useCallback, useEffect, useLayoutEffect, useMemo } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { isEmpty, get, isNil, throttle } from 'lodash' @@ -43,25 +36,23 @@ const defaultProps = { rules: {} } -let NewChipForm = ( - { - chip, - chipIndex, - chipOptions, - className = '', - editConfig, - handleRemoveChip, - isEditable, - keyName, - meta, - onChange, - setChipSizeIsRecalculated, - setEditConfig, - validationRules: rules = defaultProps.rules, - valueName - }, - ref -) => { +let NewChipForm = ({ + chip, + chipIndex, + chipOptions, + className = '', + editConfig, + handleRemoveChip, + isEditable, + keyName, + meta, + onChange, + ref, + setChipSizeIsRecalculated, + setEditConfig, + validationRules: rules = defaultProps.rules, + valueName +}) => { const [chipData, setChipData] = useState({ isKeyOnly: chip.isKeyOnly, key: chip.key, @@ -197,7 +188,9 @@ let NewChipForm = ( useEffect(() => { if (!chipData.keyFieldWidth && !chipData.valueFieldWidth) { - resizeChip() + queueMicrotask(() => { + resizeChip() + }) } }, [chipData.keyFieldWidth, chipData.valueFieldWidth, resizeChip]) @@ -371,35 +364,43 @@ let NewChipForm = ( useLayoutEffect(() => { if (editConfig.chipIndex === chipIndex) { - setSelectedInput(editConfig.isKeyFocused ? 'key' : editConfig.isValueFocused ? 'value' : null) + queueMicrotask(() => { + setSelectedInput( + editConfig.isKeyFocused ? 'key' : editConfig.isValueFocused ? 'value' : null + ) + }) } }, [editConfig.isKeyFocused, editConfig.isValueFocused, editConfig.chipIndex, chipIndex]) useEffect(() => { if (meta.valid && showValidationRules) { - setShowValidationRules(false) + queueMicrotask(() => { + setShowValidationRules(false) + }) } }, [meta.valid, showValidationRules]) useEffect(() => { if (meta.error) { - setValidationRules(prevState => { - return { - ...prevState, - [selectedInput]: prevState[selectedInput]?.map(rule => { - return { - ...rule, - isValid: isEmpty(get(meta, ['error', editConfig.chipIndex, selectedInput], [])) - ? true - : !meta.error[editConfig.chipIndex][selectedInput].some( - err => err && err.name === rule.name - ) - } - }) - } - }) + queueMicrotask(() => { + setValidationRules(prevState => { + return { + ...prevState, + [selectedInput]: prevState[selectedInput]?.map(rule => { + return { + ...rule, + isValid: isEmpty(get(meta, ['error', editConfig.chipIndex, selectedInput], [])) + ? true + : !meta.error[editConfig.chipIndex][selectedInput].some( + err => err && err.name === rule.name + ) + } + }) + } + }) - !showValidationRules && setShowValidationRules(true) + !showValidationRules && setShowValidationRules(true) + }) } }, [meta, showValidationRules, selectedInput, editConfig.chipIndex]) @@ -467,8 +468,6 @@ let NewChipForm = ( ) } -NewChipForm = forwardRef(NewChipForm) - NewChipForm.displayName = 'NewChipForm' NewChipForm.propTypes = { @@ -482,6 +481,7 @@ NewChipForm.propTypes = { keyName: PropTypes.string.isRequired, meta: PropTypes.object.isRequired, onChange: PropTypes.func.isRequired, + ref: PropTypes.object.isRequired, setChipSizeIsRecalculated: PropTypes.func.isRequired, setEditConfig: PropTypes.func.isRequired, validationRules: PropTypes.object, diff --git a/src/lib/components/FormChipCell/NewChipInput/NewChipInput.jsx b/src/lib/components/FormChipCell/NewChipInput/NewChipInput.jsx index e0f529d9..9432d372 100644 --- a/src/lib/components/FormChipCell/NewChipInput/NewChipInput.jsx +++ b/src/lib/components/FormChipCell/NewChipInput/NewChipInput.jsx @@ -14,11 +14,11 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import { Field, useField } from 'react-final-form' -let NewChipInput = ({ name, onChange, onFocus, ...inputProps }, ref) => { +let NewChipInput = ({ name, onChange, onFocus, ref, ...inputProps }) => { const { input } = useField(name) const handleInputChange = event => { @@ -51,14 +51,13 @@ let NewChipInput = ({ name, onChange, onFocus, ...inputProps }, ref) => { ) } -NewChipInput = forwardRef(NewChipInput) - NewChipInput.displayName = 'NewChipInput' NewChipInput.propTypes = { name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, - onFocus: PropTypes.func.isRequired + onFocus: PropTypes.func.isRequired, + ref: PropTypes.object.isRequired } export default NewChipInput diff --git a/src/lib/components/FormCombobox/FormCombobox.jsx b/src/lib/components/FormCombobox/FormCombobox.jsx index dd8aa97f..5033499b 100644 --- a/src/lib/components/FormCombobox/FormCombobox.jsx +++ b/src/lib/components/FormCombobox/FormCombobox.jsx @@ -74,13 +74,15 @@ const FormCombobox = ({ const [showSuggestionList, setShowSuggestionList] = useState(false) const [dropdownList, setDropdownList] = useState(suggestionList) const [searchIsFocused, setSearchIsFocused] = useState(false) - const [isInvalid, setIsInvalid] = useState(false) const [validationRules, setValidationRules] = useState(rules) const [showValidationRules, setShowValidationRules] = useState(false) const comboboxRef = useRef() const selectRef = useRef() const inputRef = useRef() const suggestionListRef = useRef() + const isInvalid = + meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) + useDetectOutsideClick(comboboxRef, () => setShowValidationRules(false)) const labelClassNames = classnames('form-field__label', disabled && 'form-field__label-disabled') @@ -90,31 +92,29 @@ const FormCombobox = ({ ) useEffect(() => { - setValidationRules(prevState => - prevState.map(rule => ({ - ...rule, - isValid: - !meta.error || !Array.isArray(meta.error) - ? true - : !meta.error.some(err => err.name === rule.name) - })) - ) + queueMicrotask(() => { + setValidationRules(prevState => + prevState.map(rule => ({ + ...rule, + isValid: + !meta.error || !Array.isArray(meta.error) + ? true + : !meta.error.some(err => err.name === rule.name) + })) + ) + }) }, [meta.error]) useEffect(() => { if (!searchIsFocused) { if (JSON.stringify(dropdownList) !== JSON.stringify(suggestionList)) { - setDropdownList(suggestionList) + queueMicrotask(() => { + setDropdownList(suggestionList) + }) } } }, [dropdownList, suggestionList, searchIsFocused]) - useEffect(() => { - setIsInvalid( - meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) - ) - }, [meta.invalid, meta.modified, meta.submitFailed, meta.touched, meta.validating]) - const handleOutsideClick = useCallback( event => { if ( diff --git a/src/lib/components/FormInput/FormInput.jsx b/src/lib/components/FormInput/FormInput.jsx index 31518cd9..6c2a971c 100644 --- a/src/lib/components/FormInput/FormInput.jsx +++ b/src/lib/components/FormInput/FormInput.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useState, useEffect, useRef, forwardRef } from 'react' +import React, { useState, useEffect, useRef } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { isEmpty, isNil } from 'lodash' @@ -46,38 +46,36 @@ const defaultProps = { rules: [] } -let FormInput = ( - { - async = false, - className = '', - customRequiredLabel = '', - density = 'normal', - disabled = false, - focused = false, - iconClass = '', - iconClick = defaultProps.iconClick, - inputIcon = null, - invalidText = 'This field is invalid', - label = '', - link = defaultProps.link, - name, - onBlur = defaultProps.onBlur, - onFocus, - onKeyDown = defaultProps.onKeyDown, - pattern = null, - required = false, - onValidationError = defaultProps.onValidationError, - suggestionList = [], - step = '1', - tip = '', - type = 'text', - validationRules: rules = defaultProps.rules, - validator = defaultProps.validator, - withoutBorder = false, - ...inputProps - }, - ref -) => { +let FormInput = ({ + async = false, + className = '', + customRequiredLabel = '', + density = 'normal', + disabled = false, + focused = false, + iconClass = '', + iconClick = defaultProps.iconClick, + inputIcon = null, + invalidText = 'This field is invalid', + label = '', + link = defaultProps.link, + name, + onBlur = defaultProps.onBlur, + onFocus, + onKeyDown = defaultProps.onKeyDown, + onValidationError = defaultProps.onValidationError, + pattern = null, + required = false, + ref, + suggestionList = [], + step = '1', + tip = '', + type = 'text', + validationRules: rules = defaultProps.rules, + validator = defaultProps.validator, + withoutBorder = false, + ...inputProps +}) => { const { input, meta } = useField(name) const [isInvalid, setIsInvalid] = useState(false) const [isFocused, setIsFocused] = useState(false) @@ -413,7 +411,7 @@ let FormInput = ( ) } -FormInput = React.memo(forwardRef(FormInput)) +FormInput = React.memo(FormInput) FormInput.displayName = 'FormInput' @@ -440,6 +438,7 @@ FormInput.propTypes = { pattern: PropTypes.string, placeholder: PropTypes.string, required: PropTypes.bool, + ref: PropTypes.object.isRequired, step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), suggestionList: PropTypes.arrayOf(PropTypes.string), tip: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), diff --git a/src/lib/components/FormOnChange/FormOnChange.jsx b/src/lib/components/FormOnChange/FormOnChange.jsx index 1abd7afa..e0986083 100644 --- a/src/lib/components/FormOnChange/FormOnChange.jsx +++ b/src/lib/components/FormOnChange/FormOnChange.jsx @@ -26,7 +26,7 @@ const OnChangeState = ({ inputValue, handler }) => { useEffect(() => { if (inputValue !== previousValue) { - setPreviousValue(inputValue) + setTimeout(() => setPreviousValue(inputValue), 0) handler(inputValue, previousValue) } }, [handler, inputValue, previousValue]) diff --git a/src/lib/components/FormSelect/FormSelect.jsx b/src/lib/components/FormSelect/FormSelect.jsx index cc086c7b..b717bb2e 100644 --- a/src/lib/components/FormSelect/FormSelect.jsx +++ b/src/lib/components/FormSelect/FormSelect.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react' +import React, { useState, useEffect, useCallback, useMemo, useRef, useLayoutEffect } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { Field, useField } from 'react-final-form' @@ -53,15 +53,17 @@ let FormSelect = ({ withoutBorder = false }) => { const { input, meta } = useField(name) - const [isInvalid, setIsInvalid] = useState(false) + const isInvalid = + meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) const [isConfirmDialogOpen, setConfirmDialogOpen] = useState(false) const [isOpen, setIsOpen] = useState(false) const [searchValue, setSearchValue] = useState('') + const [selectWidth, setSelectWidth] = useState(0) const optionsListRef = useRef() const popUpRef = useRef() const selectRef = useRef() const searchRef = useRef() - const { width: selectWidth } = selectRef?.current?.getBoundingClientRect() || {} + // const { width: selectWidth } = selectRef?.current?.getBoundingClientRect() || {} const selectWrapperClassNames = classNames( 'form-field__wrapper', @@ -82,6 +84,19 @@ let FormSelect = ({ !input.value && 'form-field__select-placeholder' ) + useLayoutEffect(() => { + if (!selectRef.current) return + + const observer = new ResizeObserver(entries => { + const { width } = entries[0].contentRect + setSelectWidth(width) + }) + + observer.observe(selectRef.current) + + return () => observer.disconnect() + }, []) + const selectedOption = options.find(option => option.id === input.value) const getFilteredOptions = useCallback( @@ -135,12 +150,6 @@ let FormSelect = ({ : `${input.value.length} items selected` } - useEffect(() => { - setIsInvalid( - meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) - ) - }, [meta.invalid, meta.modified, meta.submitFailed, meta.touched, meta.validating]) - const openMenu = useCallback(() => { if (!isOpen) { setIsOpen(true) diff --git a/src/lib/components/FormTextarea/FormTextarea.jsx b/src/lib/components/FormTextarea/FormTextarea.jsx index 91e7701c..04f2e4f0 100644 --- a/src/lib/components/FormTextarea/FormTextarea.jsx +++ b/src/lib/components/FormTextarea/FormTextarea.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef, useEffect, useLayoutEffect, useRef, useState } from 'react' +import React, { useEffect, useRef } from 'react' import classnames from 'classnames' import PropTypes from 'prop-types' import { Field, useField } from 'react-final-form' @@ -27,30 +27,29 @@ import ExclamationMarkIcon from '../../images/exclamation-mark.svg?react' import './formTextarea.scss' -let FormTextarea = ( - { - className = '', - disabled = false, - focused = false, - iconClass = '', - invalidText = 'This field is invalid', - label = '', - maxLength = null, - name, - onBlur = () => {}, - onChange = () => {}, - required = false, - rows = 3, - textAreaIcon = null, - tip = '', - withoutBorder = false, - ...textareaProps - }, - ref -) => { +let FormTextarea = ({ + className = '', + disabled = false, + focused = false, + iconClass = '', + invalidText = 'This field is invalid', + label = '', + maxLength = null, + name, + onBlur = () => {}, + onChange = () => {}, + ref, + required = false, + rows = 3, + textAreaIcon = null, + tip = '', + withoutBorder = false, + ...textareaProps +}) => { const { input, meta } = useField(name) - const [isInvalid, setIsInvalid] = useState(false) - const [textAreaCount, setTextAreaCount] = useState(input.value.length) + const isInvalid = + meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) + const textAreaCount = input.value.length const textAreaRef = useRef() const formFieldClassNames = classnames('form-field-textarea', className) @@ -62,22 +61,12 @@ let FormTextarea = ( withoutBorder && 'without-border' ) - useLayoutEffect(() => { - setTextAreaCount(input.value.length) - }, [input.value.length]) - useEffect(() => { if (focused) { textAreaRef.current.focus() } }, [focused, textAreaRef]) - useEffect(() => { - setIsInvalid( - meta.invalid && (meta.validating || meta.modified || (meta.submitFailed && meta.touched)) - ) - }, [meta.invalid, meta.modified, meta.submitFailed, meta.touched, meta.validating]) - const handleInputBlur = event => { input.onBlur(event) onBlur && onBlur(event) @@ -164,7 +153,7 @@ let FormTextarea = ( ) } -FormTextarea = React.memo(forwardRef(FormTextarea)) +FormTextarea = React.memo(FormTextarea) FormTextarea.displayName = 'FormTextarea' @@ -179,6 +168,7 @@ FormTextarea.propTypes = { name: PropTypes.string.isRequired, onBlur: PropTypes.func, onChange: PropTypes.func, + ref: PropTypes.object.isRequired, required: PropTypes.bool, rows: PropTypes.number, textAreaIcon: PropTypes.element, diff --git a/src/lib/components/LoadButton/LoadButton.jsx b/src/lib/components/LoadButton/LoadButton.jsx index 68bce6a3..da7e639a 100644 --- a/src/lib/components/LoadButton/LoadButton.jsx +++ b/src/lib/components/LoadButton/LoadButton.jsx @@ -25,10 +25,13 @@ import { PRIMARY_BUTTON, SECONDARY_BUTTON, TERTIARY_BUTTON } from '../../constan import './loadButton.scss' -let LoadButton = ( - { className = '', label = 'Load button', variant = TERTIARY_BUTTON, ...restProps }, - ref -) => { +const LoadButton = ({ + className = '', + label = 'Load button', + ref, + variant = TERTIARY_BUTTON, + ...restProps +}) => { const buttonClassName = classNames('btn-load', `btn-load-${variant}`, className) return ( @@ -38,13 +41,12 @@ let LoadButton = ( ) } -LoadButton = React.forwardRef(LoadButton) - LoadButton.displayName = 'LoadButton' LoadButton.propTypes = { className: PropTypes.string, label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), + ref: PropTypes.object.isRequired, variant: PropTypes.oneOf([PRIMARY_BUTTON, SECONDARY_BUTTON, TERTIARY_BUTTON]).isRequired } diff --git a/src/lib/components/PopUpDialog/PopUpDialog.jsx b/src/lib/components/PopUpDialog/PopUpDialog.jsx index c987bcc2..52390cf8 100644 --- a/src/lib/components/PopUpDialog/PopUpDialog.jsx +++ b/src/lib/components/PopUpDialog/PopUpDialog.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useRef } from 'react' +import React, { useCallback, useEffect, useLayoutEffect, useRef } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { createPortal } from 'react-dom' @@ -29,21 +29,19 @@ import CloseIcon from '../../images/close.svg?react' import './popUpDialog.scss' -let PopUpDialog = ( - { - children, - className = '', - closePopUp = null, - customPosition = {}, - headerIsHidden = false, - headerText = '', - isOpen = true, - onResolve = null, - style = {}, - tooltipText = '' - }, - ref -) => { +let PopUpDialog = ({ + children, + className = '', + closePopUp = null, + customPosition = {}, + headerIsHidden = false, + headerText = '', + isOpen = true, + onResolve = null, + ref, + style = {}, + tooltipText = '' +}) => { const popUpOverlayRef = useRef(null) ref ??= popUpOverlayRef const popUpClassNames = classnames( @@ -177,8 +175,6 @@ let PopUpDialog = ( : null } -PopUpDialog = forwardRef(PopUpDialog) - PopUpDialog.displayName = 'PopUpDialog' PopUpDialog.propTypes = { @@ -190,6 +186,7 @@ PopUpDialog.propTypes = { headerIsHidden: PropTypes.bool, headerText: PropTypes.string, onResolve: PropTypes.func, + ref: PropTypes.object.isRequired, showPopUpDialog: PropTypes.bool, style: PropTypes.object, tooltipText: PropTypes.string diff --git a/src/lib/components/RoundedIcon/RoundedIcon.jsx b/src/lib/components/RoundedIcon/RoundedIcon.jsx index 23deb382..62dea6cd 100644 --- a/src/lib/components/RoundedIcon/RoundedIcon.jsx +++ b/src/lib/components/RoundedIcon/RoundedIcon.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' @@ -53,7 +53,7 @@ let RoundedIcon = ( ) } -RoundedIcon = React.memo(forwardRef(RoundedIcon)) +RoundedIcon = React.memo(RoundedIcon) RoundedIcon.displayName = 'RoundedIcon' diff --git a/src/lib/components/TabsSlider/TabsSlider.jsx b/src/lib/components/TabsSlider/TabsSlider.jsx index 249805b2..d4bab1e8 100644 --- a/src/lib/components/TabsSlider/TabsSlider.jsx +++ b/src/lib/components/TabsSlider/TabsSlider.jsx @@ -144,16 +144,22 @@ const TabsSlider = ({ }, [moveToSelectedTab]) useEffect(() => { - handleHideArrows() + queueMicrotask(() => { + handleHideArrows() + }) }, [tabsList, handleHideArrows]) useEffect(() => { - moveToSelectedTab() + queueMicrotask(() => { + moveToSelectedTab() + }) }, [moveToSelectedTab]) useEffect(() => { if (params.tab && params.tab !== selectedTab && !isDetailsPopUp) { - setSelectedTab(tabsList.find(tab => tab.id === params.tab)?.id) + queueMicrotask(() => { + setSelectedTab(tabsList.find(tab => tab.id === params.tab)?.id) + }) } }, [isDetailsPopUp, params.tab, selectedTab, tabsList]) diff --git a/src/lib/components/Tip/Tip.jsx b/src/lib/components/Tip/Tip.jsx index 9d68ff64..3db85ef6 100644 --- a/src/lib/components/Tip/Tip.jsx +++ b/src/lib/components/Tip/Tip.jsx @@ -58,7 +58,7 @@ const Tip = ({ className = '', text, withExclamationMark = false }) => { const widthPosition = iconRect.left > tipRect.width - arrowOffset ? 'tip_left' : 'tip_right' const heightPosition = iconRect.top > tipRect.height + arrowLength ? 'tip_top' : 'tip_bottom' - setTipClassName(`${heightPosition} ${widthPosition}`) + queueMicrotask(() => setTipClassName(`${heightPosition} ${widthPosition}`)) if (widthPosition === 'tip_left') { const computedArrowOffset = arrowOffset + (iconLength + arrowLength) / 2 diff --git a/src/lib/components/Wizard/Wizard.jsx b/src/lib/components/Wizard/Wizard.jsx index 558cbd3d..e3a6a436 100644 --- a/src/lib/components/Wizard/Wizard.jsx +++ b/src/lib/components/Wizard/Wizard.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { isEmpty, isNumber } from 'lodash' @@ -45,32 +45,24 @@ const Wizard = ({ const wizardClasses = classNames('wizard-form', className) const [jumpingToFirstInvalid, setJumpingToFirstInvalid] = useState(false) const [activeStepNumber, setActiveStepNumber] = useState(0) - const [firstDisabledStepIdx, setFirstDisabledStepIdx] = useState(null) const visibleSteps = useMemo(() => { return stepsConfig?.filter(step => !step.hidden) || [] }, [stepsConfig]) - useLayoutEffect(() => { - const disabledStep = visibleSteps.find((step, stepIdx) => { - if (step.disabled) { - setFirstDisabledStepIdx(stepIdx) - } - - return step.disabled - }) - - if (!disabledStep) { - setFirstDisabledStepIdx(null) - } + const firstDisabledStepIdx = useMemo(() => { + const idx = visibleSteps.findIndex(step => step.disabled) + return idx === -1 ? null : idx }, [visibleSteps]) useEffect(() => { const firstInvalidStepIdx = visibleSteps.findIndex(step => step.invalid) if (jumpingToFirstInvalid && isNumber(firstInvalidStepIdx) && firstInvalidStepIdx !== -1) { - setActiveStepNumber(firstInvalidStepIdx) - setJumpingToFirstInvalid(false) + queueMicrotask(() => { + setActiveStepNumber(firstInvalidStepIdx) + setJumpingToFirstInvalid(false) + }) } }, [jumpingToFirstInvalid, visibleSteps]) diff --git a/src/lib/elements/FormActionButton/FormActionButton.jsx b/src/lib/elements/FormActionButton/FormActionButton.jsx index 46a70b3f..81f018df 100644 --- a/src/lib/elements/FormActionButton/FormActionButton.jsx +++ b/src/lib/elements/FormActionButton/FormActionButton.jsx @@ -17,23 +17,21 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import Plus from '../../images/plus.svg?react' -let FormActionButton = ( - { - disabled = false, - fields, - fieldsPath, - hidden = false, - id = '', - label = 'Add new item', - onClick - }, +let FormActionButton = ({ + disabled = false, + fields, + fieldsPath, + hidden = false, + id = '', + label = 'Add new item', + onClick, ref -) => { +}) => { return ( <> {!hidden && ( @@ -54,8 +52,6 @@ let FormActionButton = ( ) } -FormActionButton = forwardRef(FormActionButton) - FormActionButton.displayName = 'FormActionButton' FormActionButton.propTypes = { @@ -65,7 +61,8 @@ FormActionButton.propTypes = { hidden: PropTypes.bool, id: PropTypes.string, label: PropTypes.string, - onClick: PropTypes.func.isRequired + onClick: PropTypes.func.isRequired, + ref: PropTypes.object.isRequired } export default FormActionButton diff --git a/src/lib/elements/OptionsMenu/OptionsMenu.jsx b/src/lib/elements/OptionsMenu/OptionsMenu.jsx index 3114c53d..730ef24f 100644 --- a/src/lib/elements/OptionsMenu/OptionsMenu.jsx +++ b/src/lib/elements/OptionsMenu/OptionsMenu.jsx @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef, useRef } from 'react' +import React, { useRef } from 'react' import PropTypes from 'prop-types' import { CSSTransition } from 'react-transition-group' @@ -22,10 +22,8 @@ import PopUpDialog from '../../components/PopUpDialog/PopUpDialog' import './optionsMenu.scss' -let OptionsMenu = ( - { children = [], show, timeout = 300 }, - { refInputContainer, validationRulesRef } -) => { +let OptionsMenu = ({ children = [], ref, show, timeout = 300 }) => { + let { refInputContainer, validationRulesRef } = ref const { width: dropdownWidth } = refInputContainer?.current ? refInputContainer.current.getBoundingClientRect() : {} @@ -58,12 +56,11 @@ let OptionsMenu = ( ) } -OptionsMenu = forwardRef(OptionsMenu) - OptionsMenu.displayName = 'OptionsMenu' OptionsMenu.propTypes = { children: PropTypes.arrayOf(PropTypes.element), + ref: PropTypes.object.isRequired, show: PropTypes.bool, timeout: PropTypes.number } diff --git a/src/lib/elements/TableHead/TableHead.jsx b/src/lib/elements/TableHead/TableHead.jsx index dc16903c..c481a8fa 100644 --- a/src/lib/elements/TableHead/TableHead.jsx +++ b/src/lib/elements/TableHead/TableHead.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { forwardRef } from 'react' +import React from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { isEmpty } from 'lodash' @@ -28,10 +28,14 @@ import TextTooltipTemplate from '../../components/TooltipTemplate/TextTooltipTem import { SORT_PROPS } from '../../types' -let TableHead = ( - { content, hideActionsMenu = false, mainRowItemsCount, selectedItem, sortProps = null }, - ref -) => { +let TableHead = ({ + content, + hideActionsMenu = false, + mainRowItemsCount, + ref, + selectedItem, + sortProps = null +}) => { const getHeaderCellClasses = ( headerId, isSortable, @@ -82,14 +86,13 @@ let TableHead = ( ) } -TableHead = forwardRef(TableHead) - TableHead.displayName = 'TableHead' TableHead.propTypes = { content: PropTypes.array.isRequired, hideActionsMenu: PropTypes.bool, mainRowItemsCount: PropTypes.number.isRequired, + ref: PropTypes.object.isRequired, selectedItem: PropTypes.object.isRequired, sortProps: SORT_PROPS } diff --git a/src/lib/hooks/useChipCell.hook.js b/src/lib/hooks/useChipCell.hook.js index db140b03..646da771 100644 --- a/src/lib/hooks/useChipCell.hook.js +++ b/src/lib/hooks/useChipCell.hook.js @@ -138,7 +138,7 @@ export const useChipCell = (isEditMode, visibleChipsMaxLength) => { }, [chipBlockMarginRight, chipsSizes, isEditMode]) useLayoutEffect(() => { - resizeChipCell() + requestAnimationFrame(() => resizeChipCell()) }, [resizeChipCell]) useEffect(() => { diff --git a/src/lib/hooks/useDetails.hook.jsx b/src/lib/hooks/useDetails.hook.jsx index 15037b9e..96088ae5 100644 --- a/src/lib/hooks/useDetails.hook.jsx +++ b/src/lib/hooks/useDetails.hook.jsx @@ -57,7 +57,7 @@ const DetailsContainer = ({ detailsRef, detailsStore, doNotLeavePage, - formRef, + form, isDetailsPopUp = null, leavePage, params, @@ -69,7 +69,7 @@ const DetailsContainer = ({ withActionMenu = true }) => { return ( -
{}}> + {}}> {formState => (
{detailsStore.loadingCounter > 0 && } @@ -123,7 +123,7 @@ DetailsContainer.propTypes = { detailsStore: PropTypes.object.isRequired, commonDetailsStore: PropTypes.object.isRequired, doNotLeavePage: PropTypes.func.isRequired, - formRef: PropTypes.object.isRequired, + form: PropTypes.object.isRequired, isDetailsPopUp: PropTypes.bool, leavePage: PropTypes.func.isRequired, params: PropTypes.object.isRequired, @@ -165,13 +165,11 @@ export const useDetails = ({ isDetailsPopUp && 'table__item-popup' ) - const formRef = useRef( - createForm({ - initialValues: formInitialValues, - mutators: { ...arrayMutators, setFieldState }, - onSubmit: () => {} - }) - ) + const form = createForm({ + initialValues: formInitialValues, + mutators: { ...arrayMutators, setFieldState }, + onSubmit: () => {} + }) useEffect(() => { return () => { @@ -229,14 +227,14 @@ export const useDetails = ({ useEffect(() => { if ( - formRef.current && + form && commonDetailsStore.changes.counter === 0 && - !isEqual(pickBy(formInitialValues), pickBy(formRef.current.getState()?.values)) && - !formRef.current.getState()?.active + !isEqual(pickBy(formInitialValues), pickBy(form.getState()?.values)) && + !form.getState()?.active ) { - formRef.current.restart(formInitialValues) + form.restart(formInitialValues) } - }, [formInitialValues, commonDetailsStore.changes.counter]) + }, [formInitialValues, commonDetailsStore.changes.counter, form]) useEffect(() => { const currentPathname = location.pathname.substring( @@ -245,11 +243,11 @@ export const useDetails = ({ ) if (previousPathnameRef.current !== currentPathname && !isDetailsPopUp) { - formRef.current.restart(formInitialValues) + form.restart(formInitialValues) dispatch(setEditMode(false)) previousPathnameRef.current = currentPathname } - }, [dispatch, formInitialValues, isDetailsPopUp, location.pathname, params.tab]) + }, [dispatch, form, formInitialValues, isDetailsPopUp, location.pathname, params.tab]) const applyChanges = useCallback(() => { applyDetailsChanges(commonDetailsStore.changes) @@ -275,9 +273,9 @@ export const useDetails = ({ const cancelChanges = useCallback(() => { if (commonDetailsStore.changes.counter > 0) { dispatch(resetChanges()) - formRef.current.reset(formInitialValues) + form.reset(formInitialValues) } - }, [commonDetailsStore.changes.counter, dispatch, formInitialValues]) + }, [commonDetailsStore.changes.counter, dispatch, form, formInitialValues]) const leavePage = useCallback(() => { cancelChanges() @@ -308,7 +306,7 @@ export const useDetails = ({ detailsRef, commonDetailsStore, doNotLeavePage, - formRef, + form, handleShowWarning, leavePage, location, diff --git a/src/lib/hooks/useHiddenChipsBlock.hook.js b/src/lib/hooks/useHiddenChipsBlock.hook.js index 3b45e301..9363903d 100644 --- a/src/lib/hooks/useHiddenChipsBlock.hook.js +++ b/src/lib/hooks/useHiddenChipsBlock.hook.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react' import classnames from 'classnames' import { getTransitionEndEventName } from '../utils/common.util' @@ -108,8 +108,8 @@ export const useHiddenChipsBlock = (hiddenChipsCounterRef, hiddenChipsPopUpRef) } }, [hiddenChipsPopUpRef, hiddenChipsCounterRef, resizePopUp, transitionEndEventName]) - useEffect(() => { - resizePopUp() + useLayoutEffect(() => { + queueMicrotask(() => resizePopUp()) }, [resizePopUp]) return {