@doyourjob/gravity-ui-page-constructor-addons 2.1.47 → 2.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,18 @@
10
10
  npm install @gravity-ui/page-constructor-addons
11
11
  ```
12
12
 
13
+ ## Release patch
14
+
15
+ Run from a clean branch with an upstream configured:
16
+
17
+ ```shell
18
+ pnpm bump-patch-release
19
+ ```
20
+
21
+ The script fetches the upstream remote, refuses to continue if upstream has commits missing
22
+ locally, bumps the package patch version, commits `chore: release vX.Y.Z`, creates the
23
+ `vX.Y.Z` tag, then pushes the commit and tag.
24
+
13
25
  ## Development
14
26
 
15
27
  ```bash
@@ -122,6 +122,11 @@ unpredictable css rules order in build */
122
122
  text-decoration: none;
123
123
  }
124
124
 
125
+ .pc-addons-header-stripe__item-link:focus-visible {
126
+ outline: 2px solid var(--g-color-line-focus);
127
+ outline-offset: -2px;
128
+ }
129
+
125
130
  @media (min-width: 769px) {
126
131
  .pc-addons-header-stripe__item-link {
127
132
  overflow: hidden;
@@ -147,6 +152,11 @@ unpredictable css rules order in build */
147
152
  opacity: 0.6;
148
153
  }
149
154
 
155
+ .pc-addons-header-stripe__close:focus-visible {
156
+ outline: 2px solid var(--g-color-line-focus);
157
+ outline-offset: -2px;
158
+ }
159
+
150
160
  @keyframes expand-mobile {
151
161
  from {
152
162
  max-height: 0;
@@ -10,12 +10,12 @@ const cn_1 = require("../../utils/cn");
10
10
  const CloseIcon_1 = require("./CloseIcon");
11
11
  const i18n_1 = tslib_1.__importDefault(require("./i18n"));
12
12
  const b = (0, cn_1.block)('header-stripe');
13
- const renderItemContent = (item) => {
13
+ const renderItemContent = (item, isActive) => {
14
14
  if (typeof item === 'string') {
15
15
  return item;
16
16
  }
17
17
  else if (item.link) {
18
- return (react_1.default.createElement("a", { className: b('item-link'), href: item.link, target: item.target }, item.text));
18
+ return (react_1.default.createElement("a", { className: b('item-link'), href: item.link, target: item.target, tabIndex: isActive ? undefined : -1 }, item.text));
19
19
  }
20
20
  else {
21
21
  return item.text;
@@ -24,6 +24,7 @@ const renderItemContent = (item) => {
24
24
  const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroundImage, onlyDesktop, canClose, onClose, newDesign, }) => {
25
25
  const [activeIndex, setActiveIndex] = (0, react_1.useState)(0);
26
26
  const [isClosing, setIsClosing] = (0, react_1.useState)(false);
27
+ const [isFocusInside, setIsFocusInside] = (0, react_1.useState)(false);
27
28
  const isMobile = (0, uikit_1.useMobile)();
28
29
  const filteredItems = (0, react_1.useMemo)(() => isMobile
29
30
  ? items.filter((item) => (typeof item === 'object' ? !item.onlyDesktop : true))
@@ -32,13 +33,23 @@ const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroun
32
33
  setIsClosing(true);
33
34
  onClose === null || onClose === void 0 ? void 0 : onClose();
34
35
  }, [onClose]);
36
+ const handleFocus = (0, react_1.useCallback)(() => {
37
+ setIsFocusInside(true);
38
+ }, []);
39
+ const handleBlur = (0, react_1.useCallback)((event) => {
40
+ const nextFocusedElement = event.relatedTarget;
41
+ if (!(nextFocusedElement instanceof Node) ||
42
+ !event.currentTarget.contains(nextFocusedElement)) {
43
+ setIsFocusInside(false);
44
+ }
45
+ }, []);
35
46
  (0, react_1.useEffect)(() => {
36
47
  if (filteredItems.length > 0) {
37
48
  setActiveIndex(0);
38
49
  }
39
50
  }, [filteredItems.length]);
40
51
  (0, react_1.useEffect)(() => {
41
- if (filteredItems.length < 1)
52
+ if (filteredItems.length < 2 || isFocusInside)
42
53
  return undefined;
43
54
  const interval = setInterval(() => {
44
55
  setActiveIndex((prevIndex) => (prevIndex + 1) % filteredItems.length);
@@ -46,7 +57,7 @@ const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroun
46
57
  return () => {
47
58
  clearInterval(interval);
48
59
  };
49
- }, [duration, filteredItems.length]);
60
+ }, [duration, filteredItems.length, isFocusInside]);
50
61
  const rootStyle = (0, react_1.useMemo)(() => {
51
62
  const properties = {};
52
63
  if (background) {
@@ -81,7 +92,7 @@ const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroun
81
92
  }), style: rootStyle },
82
93
  react_1.default.createElement(gravity_ui_page_constructor_1.Grid, null,
83
94
  react_1.default.createElement(gravity_ui_page_constructor_1.Col, null,
84
- react_1.default.createElement("div", { className: b('content', { 'with-close': Boolean(onClose) }), style: contentStyle },
95
+ react_1.default.createElement("div", { className: b('content', { 'with-close': Boolean(onClose) }), style: contentStyle, onFocus: handleFocus, onBlur: handleBlur },
85
96
  filteredItems.map((item, index) => {
86
97
  const isActive = index === activeIndex;
87
98
  const isPrev = filteredItems.length > 1 &&
@@ -92,8 +103,8 @@ const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroun
92
103
  return (react_1.default.createElement("div", { key: String(index), className: b('item', {
93
104
  active: isActive,
94
105
  prev: isPrev,
95
- }) },
96
- react_1.default.createElement("div", { className: b('item-content') }, renderItemContent(item))));
106
+ }), "aria-hidden": !isActive },
107
+ react_1.default.createElement("div", { className: b('item-content') }, renderItemContent(item, isActive))));
97
108
  }),
98
109
  canClose && (react_1.default.createElement("button", { "aria-label": (0, i18n_1.default)('close'), className: b('close'), onClick: handleClose },
99
110
  react_1.default.createElement(uikit_1.Icon, { data: newDesign ? CloseIcon_1.CloseIcon : icons_1.Xmark, className: b('close-icon'), size: 16 }))))))));
@@ -1,3 +1,8 @@
1
+ .pc-addons-nh-logo:focus-visible {
2
+ outline: 2px solid var(--g-color-line-focus);
3
+ outline-offset: 4px;
4
+ }
5
+
1
6
  .pc-addons-nh-logo__img {
2
7
  display: block;
3
8
  height: 36px;
@@ -122,6 +122,11 @@ unpredictable css rules order in build */
122
122
  text-decoration: none;
123
123
  }
124
124
 
125
+ .pc-addons-header-stripe__item-link:focus-visible {
126
+ outline: 2px solid var(--g-color-line-focus);
127
+ outline-offset: -2px;
128
+ }
129
+
125
130
  @media (min-width: 769px) {
126
131
  .pc-addons-header-stripe__item-link {
127
132
  overflow: hidden;
@@ -147,6 +152,11 @@ unpredictable css rules order in build */
147
152
  opacity: 0.6;
148
153
  }
149
154
 
155
+ .pc-addons-header-stripe__close:focus-visible {
156
+ outline: 2px solid var(--g-color-line-focus);
157
+ outline-offset: -2px;
158
+ }
159
+
150
160
  @keyframes expand-mobile {
151
161
  from {
152
162
  max-height: 0;
@@ -7,12 +7,12 @@ import { CloseIcon } from './CloseIcon';
7
7
  import i18n from './i18n';
8
8
  import './HeaderStripe.css';
9
9
  const b = block('header-stripe');
10
- const renderItemContent = (item) => {
10
+ const renderItemContent = (item, isActive) => {
11
11
  if (typeof item === 'string') {
12
12
  return item;
13
13
  }
14
14
  else if (item.link) {
15
- return (React.createElement("a", { className: b('item-link'), href: item.link, target: item.target }, item.text));
15
+ return (React.createElement("a", { className: b('item-link'), href: item.link, target: item.target, tabIndex: isActive ? undefined : -1 }, item.text));
16
16
  }
17
17
  else {
18
18
  return item.text;
@@ -21,6 +21,7 @@ const renderItemContent = (item) => {
21
21
  export const HeaderStripe = ({ duration = 8000, items, textColor, background, backgroundImage, onlyDesktop, canClose, onClose, newDesign, }) => {
22
22
  const [activeIndex, setActiveIndex] = useState(0);
23
23
  const [isClosing, setIsClosing] = useState(false);
24
+ const [isFocusInside, setIsFocusInside] = useState(false);
24
25
  const isMobile = useMobile();
25
26
  const filteredItems = useMemo(() => isMobile
26
27
  ? items.filter((item) => (typeof item === 'object' ? !item.onlyDesktop : true))
@@ -29,13 +30,23 @@ export const HeaderStripe = ({ duration = 8000, items, textColor, background, ba
29
30
  setIsClosing(true);
30
31
  onClose === null || onClose === void 0 ? void 0 : onClose();
31
32
  }, [onClose]);
33
+ const handleFocus = useCallback(() => {
34
+ setIsFocusInside(true);
35
+ }, []);
36
+ const handleBlur = useCallback((event) => {
37
+ const nextFocusedElement = event.relatedTarget;
38
+ if (!(nextFocusedElement instanceof Node) ||
39
+ !event.currentTarget.contains(nextFocusedElement)) {
40
+ setIsFocusInside(false);
41
+ }
42
+ }, []);
32
43
  useEffect(() => {
33
44
  if (filteredItems.length > 0) {
34
45
  setActiveIndex(0);
35
46
  }
36
47
  }, [filteredItems.length]);
37
48
  useEffect(() => {
38
- if (filteredItems.length < 1)
49
+ if (filteredItems.length < 2 || isFocusInside)
39
50
  return undefined;
40
51
  const interval = setInterval(() => {
41
52
  setActiveIndex((prevIndex) => (prevIndex + 1) % filteredItems.length);
@@ -43,7 +54,7 @@ export const HeaderStripe = ({ duration = 8000, items, textColor, background, ba
43
54
  return () => {
44
55
  clearInterval(interval);
45
56
  };
46
- }, [duration, filteredItems.length]);
57
+ }, [duration, filteredItems.length, isFocusInside]);
47
58
  const rootStyle = useMemo(() => {
48
59
  const properties = {};
49
60
  if (background) {
@@ -78,7 +89,7 @@ export const HeaderStripe = ({ duration = 8000, items, textColor, background, ba
78
89
  }), style: rootStyle },
79
90
  React.createElement(Grid, null,
80
91
  React.createElement(Col, null,
81
- React.createElement("div", { className: b('content', { 'with-close': Boolean(onClose) }), style: contentStyle },
92
+ React.createElement("div", { className: b('content', { 'with-close': Boolean(onClose) }), style: contentStyle, onFocus: handleFocus, onBlur: handleBlur },
82
93
  filteredItems.map((item, index) => {
83
94
  const isActive = index === activeIndex;
84
95
  const isPrev = filteredItems.length > 1 &&
@@ -89,8 +100,8 @@ export const HeaderStripe = ({ duration = 8000, items, textColor, background, ba
89
100
  return (React.createElement("div", { key: String(index), className: b('item', {
90
101
  active: isActive,
91
102
  prev: isPrev,
92
- }) },
93
- React.createElement("div", { className: b('item-content') }, renderItemContent(item))));
103
+ }), "aria-hidden": !isActive },
104
+ React.createElement("div", { className: b('item-content') }, renderItemContent(item, isActive))));
94
105
  }),
95
106
  canClose && (React.createElement("button", { "aria-label": i18n('close'), className: b('close'), onClick: handleClose },
96
107
  React.createElement(Icon, { data: newDesign ? CloseIcon : Xmark, className: b('close-icon'), size: 16 }))))))));
@@ -1,3 +1,8 @@
1
+ .pc-addons-nh-logo:focus-visible {
2
+ outline: 2px solid var(--g-color-line-focus);
3
+ outline-offset: 4px;
4
+ }
5
+
1
6
  .pc-addons-nh-logo__img {
2
7
  display: block;
3
8
  height: 36px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doyourjob/gravity-ui-page-constructor-addons",
3
- "version": "2.1.47",
3
+ "version": "2.1.49",
4
4
  "description": "Components and plugins for @doyourjob/gravity-ui-page-constructor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,6 +42,7 @@
42
42
  "*.scss"
43
43
  ],
44
44
  "scripts": {
45
+ "bump-patch-release": "node ./scripts/bump-patch.mjs",
45
46
  "deps:install": "npm ci",
46
47
  "deps:truncate": "npm prune --production",
47
48
  "lint:fix": "run-s lint:js:fix lint:styles:fix lint:prettier:fix typecheck",