@atlaskit/editor-toolbar 0.15.4 → 0.16.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-toolbar
2
2
 
3
+ ## 0.16.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`238f9a879ab1d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/238f9a879ab1d) -
8
+ Add left and right arrow keyboard shortcuts to selection toolbar
9
+
10
+ ## 0.16.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [`0d64de95a912a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0d64de95a912a) -
15
+ Allow editor ToolbarButton to take id as a prop
16
+
3
17
  ## 0.15.4
4
18
 
5
19
  ### Patch Changes
@@ -31,6 +31,7 @@ var ToolbarButton = exports.ToolbarButton = /*#__PURE__*/(0, _react.forwardRef)(
31
31
  onBlur = _ref.onBlur,
32
32
  onFocus = _ref.onFocus,
33
33
  testId = _ref.testId,
34
+ id = _ref.id,
34
35
  isDisabled = _ref.isDisabled,
35
36
  ariaKeyshortcuts = _ref.ariaKeyshortcuts,
36
37
  label = _ref.label,
@@ -53,6 +54,7 @@ var ToolbarButton = exports.ToolbarButton = /*#__PURE__*/(0, _react.forwardRef)(
53
54
  onBlur: onBlur,
54
55
  onFocus: onFocus,
55
56
  testId: testId,
57
+ id: id,
56
58
  isDisabled: disabled,
57
59
  onMouseDown: function onMouseDown(event) {
58
60
  if (preventDefaultOnMouseDown) {
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.ToolbarKeyboardNavigationProvider = void 0;
8
8
  var _react = _interopRequireWildcard(require("react"));
9
+ var _browserApis = require("@atlaskit/browser-apis");
10
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
11
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
10
12
  var ToolbarKeyboardNavigationProvider = exports.ToolbarKeyboardNavigationProvider = function ToolbarKeyboardNavigationProvider(_ref) {
11
13
  var children = _ref.children,
@@ -22,16 +24,84 @@ var ToolbarKeyboardNavigationProvider = exports.ToolbarKeyboardNavigationProvide
22
24
  return;
23
25
  }
24
26
  var element = wrapperRef.current;
27
+ var getFocusableElements = function getFocusableElements() {
28
+ if (!element) {
29
+ return [];
30
+ }
31
+ // Find all focusable elements within the toolbar that match the child component selector
32
+ var focusableSelectors = ['button:not([disabled])', '[role="button"]:not([disabled])', '[tabindex]:not([tabindex="-1"])'].join(',');
33
+ var allFocusable = Array.from(element.querySelectorAll(focusableSelectors));
34
+
35
+ // Filter to only include elements that are:
36
+ // 1. Within the child component selector
37
+ // 2. Visible (not hidden by display:none on itself or any parent)
38
+ return allFocusable.filter(function (el) {
39
+ if (!el.closest("".concat(childComponentSelector))) {
40
+ return false;
41
+ }
42
+
43
+ // Check if the element or any of its parents have display: none
44
+ var currentEl = el;
45
+ while (currentEl && currentEl !== element) {
46
+ var computedStyle = window.getComputedStyle(currentEl);
47
+ if (computedStyle.display === 'none' || computedStyle.visibility === 'hidden') {
48
+ return false;
49
+ }
50
+ currentEl = currentEl.parentElement;
51
+ }
52
+ return true;
53
+ });
54
+ };
55
+ var moveFocus = function moveFocus(direction) {
56
+ var _focusableElements$ne;
57
+ var focusableElements = getFocusableElements();
58
+ if (focusableElements.length === 0) {
59
+ return;
60
+ }
61
+ var doc = (0, _browserApis.getDocument)();
62
+ var currentIndex = focusableElements.findIndex(function (el) {
63
+ return el === (doc === null || doc === void 0 ? void 0 : doc.activeElement);
64
+ });
65
+ var nextIndex;
66
+ if (currentIndex === -1) {
67
+ // No element currently focused, focus the first one
68
+ nextIndex = 0;
69
+ } else if (direction === 'right') {
70
+ // Move right, wrap to beginning if at end
71
+ nextIndex = (currentIndex + 1) % focusableElements.length;
72
+ } else {
73
+ // Move left, wrap to end if at beginning
74
+ nextIndex = currentIndex === 0 ? focusableElements.length - 1 : currentIndex - 1;
75
+ }
76
+ (_focusableElements$ne = focusableElements[nextIndex]) === null || _focusableElements$ne === void 0 || _focusableElements$ne.focus();
77
+ };
25
78
  var handleKeyDown = function handleKeyDown(event) {
26
79
  var targetElement = event.target;
27
80
  if (targetElement instanceof HTMLElement && !targetElement.closest("".concat(childComponentSelector))) {
28
81
  return;
29
82
  }
30
- switch (event.key) {
31
- case 'Escape':
32
- handleEscape(event);
33
- break;
34
- default:
83
+ if ((0, _platformFeatureFlags.fg)('platform_editor_toolbar_aifc_patch_7')) {
84
+ switch (event.key) {
85
+ case 'Escape':
86
+ handleEscape(event);
87
+ break;
88
+ case 'ArrowLeft':
89
+ event.preventDefault();
90
+ moveFocus('left');
91
+ break;
92
+ case 'ArrowRight':
93
+ event.preventDefault();
94
+ moveFocus('right');
95
+ break;
96
+ default:
97
+ }
98
+ } else {
99
+ switch (event.key) {
100
+ case 'Escape':
101
+ handleEscape(event);
102
+ break;
103
+ default:
104
+ }
35
105
  }
36
106
  };
37
107
  var globalKeyDownHandler = function globalKeyDownHandler(event) {
@@ -23,6 +23,7 @@ export const ToolbarButton = /*#__PURE__*/forwardRef(({
23
23
  onBlur,
24
24
  onFocus,
25
25
  testId,
26
+ id,
26
27
  isDisabled,
27
28
  ariaKeyshortcuts,
28
29
  label,
@@ -47,6 +48,7 @@ export const ToolbarButton = /*#__PURE__*/forwardRef(({
47
48
  onBlur: onBlur,
48
49
  onFocus: onFocus,
49
50
  testId: testId,
51
+ id: id,
50
52
  isDisabled: disabled,
51
53
  onMouseDown: event => {
52
54
  if (preventDefaultOnMouseDown) {
@@ -1,4 +1,6 @@
1
1
  import React, { useLayoutEffect, useRef } from 'react';
2
+ import { getDocument } from '@atlaskit/browser-apis';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
2
4
  export const ToolbarKeyboardNavigationProvider = ({
3
5
  children,
4
6
  childComponentSelector,
@@ -17,16 +19,82 @@ export const ToolbarKeyboardNavigationProvider = ({
17
19
  const {
18
20
  current: element
19
21
  } = wrapperRef;
22
+ const getFocusableElements = () => {
23
+ if (!element) {
24
+ return [];
25
+ }
26
+ // Find all focusable elements within the toolbar that match the child component selector
27
+ const focusableSelectors = ['button:not([disabled])', '[role="button"]:not([disabled])', '[tabindex]:not([tabindex="-1"])'].join(',');
28
+ const allFocusable = Array.from(element.querySelectorAll(focusableSelectors));
29
+
30
+ // Filter to only include elements that are:
31
+ // 1. Within the child component selector
32
+ // 2. Visible (not hidden by display:none on itself or any parent)
33
+ return allFocusable.filter(el => {
34
+ if (!el.closest(`${childComponentSelector}`)) {
35
+ return false;
36
+ }
37
+
38
+ // Check if the element or any of its parents have display: none
39
+ let currentEl = el;
40
+ while (currentEl && currentEl !== element) {
41
+ const computedStyle = window.getComputedStyle(currentEl);
42
+ if (computedStyle.display === 'none' || computedStyle.visibility === 'hidden') {
43
+ return false;
44
+ }
45
+ currentEl = currentEl.parentElement;
46
+ }
47
+ return true;
48
+ });
49
+ };
50
+ const moveFocus = direction => {
51
+ var _focusableElements$ne;
52
+ const focusableElements = getFocusableElements();
53
+ if (focusableElements.length === 0) {
54
+ return;
55
+ }
56
+ const doc = getDocument();
57
+ const currentIndex = focusableElements.findIndex(el => el === (doc === null || doc === void 0 ? void 0 : doc.activeElement));
58
+ let nextIndex;
59
+ if (currentIndex === -1) {
60
+ // No element currently focused, focus the first one
61
+ nextIndex = 0;
62
+ } else if (direction === 'right') {
63
+ // Move right, wrap to beginning if at end
64
+ nextIndex = (currentIndex + 1) % focusableElements.length;
65
+ } else {
66
+ // Move left, wrap to end if at beginning
67
+ nextIndex = currentIndex === 0 ? focusableElements.length - 1 : currentIndex - 1;
68
+ }
69
+ (_focusableElements$ne = focusableElements[nextIndex]) === null || _focusableElements$ne === void 0 ? void 0 : _focusableElements$ne.focus();
70
+ };
20
71
  const handleKeyDown = event => {
21
72
  const targetElement = event.target;
22
73
  if (targetElement instanceof HTMLElement && !targetElement.closest(`${childComponentSelector}`)) {
23
74
  return;
24
75
  }
25
- switch (event.key) {
26
- case 'Escape':
27
- handleEscape(event);
28
- break;
29
- default:
76
+ if (fg('platform_editor_toolbar_aifc_patch_7')) {
77
+ switch (event.key) {
78
+ case 'Escape':
79
+ handleEscape(event);
80
+ break;
81
+ case 'ArrowLeft':
82
+ event.preventDefault();
83
+ moveFocus('left');
84
+ break;
85
+ case 'ArrowRight':
86
+ event.preventDefault();
87
+ moveFocus('right');
88
+ break;
89
+ default:
90
+ }
91
+ } else {
92
+ switch (event.key) {
93
+ case 'Escape':
94
+ handleEscape(event);
95
+ break;
96
+ default:
97
+ }
30
98
  }
31
99
  };
32
100
  const globalKeyDownHandler = event => {
@@ -23,6 +23,7 @@ export var ToolbarButton = /*#__PURE__*/forwardRef(function (_ref, ref) {
23
23
  onBlur = _ref.onBlur,
24
24
  onFocus = _ref.onFocus,
25
25
  testId = _ref.testId,
26
+ id = _ref.id,
26
27
  isDisabled = _ref.isDisabled,
27
28
  ariaKeyshortcuts = _ref.ariaKeyshortcuts,
28
29
  label = _ref.label,
@@ -45,6 +46,7 @@ export var ToolbarButton = /*#__PURE__*/forwardRef(function (_ref, ref) {
45
46
  onBlur: onBlur,
46
47
  onFocus: onFocus,
47
48
  testId: testId,
49
+ id: id,
48
50
  isDisabled: disabled,
49
51
  onMouseDown: function onMouseDown(event) {
50
52
  if (preventDefaultOnMouseDown) {
@@ -1,4 +1,6 @@
1
1
  import React, { useLayoutEffect, useRef } from 'react';
2
+ import { getDocument } from '@atlaskit/browser-apis';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
2
4
  export var ToolbarKeyboardNavigationProvider = function ToolbarKeyboardNavigationProvider(_ref) {
3
5
  var children = _ref.children,
4
6
  childComponentSelector = _ref.childComponentSelector,
@@ -14,16 +16,84 @@ export var ToolbarKeyboardNavigationProvider = function ToolbarKeyboardNavigatio
14
16
  return;
15
17
  }
16
18
  var element = wrapperRef.current;
19
+ var getFocusableElements = function getFocusableElements() {
20
+ if (!element) {
21
+ return [];
22
+ }
23
+ // Find all focusable elements within the toolbar that match the child component selector
24
+ var focusableSelectors = ['button:not([disabled])', '[role="button"]:not([disabled])', '[tabindex]:not([tabindex="-1"])'].join(',');
25
+ var allFocusable = Array.from(element.querySelectorAll(focusableSelectors));
26
+
27
+ // Filter to only include elements that are:
28
+ // 1. Within the child component selector
29
+ // 2. Visible (not hidden by display:none on itself or any parent)
30
+ return allFocusable.filter(function (el) {
31
+ if (!el.closest("".concat(childComponentSelector))) {
32
+ return false;
33
+ }
34
+
35
+ // Check if the element or any of its parents have display: none
36
+ var currentEl = el;
37
+ while (currentEl && currentEl !== element) {
38
+ var computedStyle = window.getComputedStyle(currentEl);
39
+ if (computedStyle.display === 'none' || computedStyle.visibility === 'hidden') {
40
+ return false;
41
+ }
42
+ currentEl = currentEl.parentElement;
43
+ }
44
+ return true;
45
+ });
46
+ };
47
+ var moveFocus = function moveFocus(direction) {
48
+ var _focusableElements$ne;
49
+ var focusableElements = getFocusableElements();
50
+ if (focusableElements.length === 0) {
51
+ return;
52
+ }
53
+ var doc = getDocument();
54
+ var currentIndex = focusableElements.findIndex(function (el) {
55
+ return el === (doc === null || doc === void 0 ? void 0 : doc.activeElement);
56
+ });
57
+ var nextIndex;
58
+ if (currentIndex === -1) {
59
+ // No element currently focused, focus the first one
60
+ nextIndex = 0;
61
+ } else if (direction === 'right') {
62
+ // Move right, wrap to beginning if at end
63
+ nextIndex = (currentIndex + 1) % focusableElements.length;
64
+ } else {
65
+ // Move left, wrap to end if at beginning
66
+ nextIndex = currentIndex === 0 ? focusableElements.length - 1 : currentIndex - 1;
67
+ }
68
+ (_focusableElements$ne = focusableElements[nextIndex]) === null || _focusableElements$ne === void 0 || _focusableElements$ne.focus();
69
+ };
17
70
  var handleKeyDown = function handleKeyDown(event) {
18
71
  var targetElement = event.target;
19
72
  if (targetElement instanceof HTMLElement && !targetElement.closest("".concat(childComponentSelector))) {
20
73
  return;
21
74
  }
22
- switch (event.key) {
23
- case 'Escape':
24
- handleEscape(event);
25
- break;
26
- default:
75
+ if (fg('platform_editor_toolbar_aifc_patch_7')) {
76
+ switch (event.key) {
77
+ case 'Escape':
78
+ handleEscape(event);
79
+ break;
80
+ case 'ArrowLeft':
81
+ event.preventDefault();
82
+ moveFocus('left');
83
+ break;
84
+ case 'ArrowRight':
85
+ event.preventDefault();
86
+ moveFocus('right');
87
+ break;
88
+ default:
89
+ }
90
+ } else {
91
+ switch (event.key) {
92
+ case 'Escape':
93
+ handleEscape(event);
94
+ break;
95
+ default:
96
+ }
27
97
  }
28
98
  };
29
99
  var globalKeyDownHandler = function globalKeyDownHandler(event) {
@@ -4,6 +4,7 @@ type ToolbarButtonProps = Partial<TriggerProps> & {
4
4
  ariaKeyshortcuts?: string;
5
5
  children?: ReactNode;
6
6
  iconBefore: React.ReactNode;
7
+ id?: string;
7
8
  interactionName?: string;
8
9
  isDisabled?: boolean;
9
10
  isSelected?: boolean;
@@ -4,6 +4,7 @@ type ToolbarButtonProps = Partial<TriggerProps> & {
4
4
  ariaKeyshortcuts?: string;
5
5
  children?: ReactNode;
6
6
  iconBefore: React.ReactNode;
7
+ id?: string;
7
8
  interactionName?: string;
8
9
  isDisabled?: boolean;
9
10
  isSelected?: boolean;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "registry": "https://registry.npmjs.org/"
5
5
  },
6
- "version": "0.15.4",
6
+ "version": "0.16.1",
7
7
  "description": "Common UI for Toolbars across the platform",
8
8
  "atlassian": {
9
9
  "team": "Editor: Jenga",
@@ -22,6 +22,7 @@
22
22
  "atlaskit:src": "src/index.ts",
23
23
  "dependencies": {
24
24
  "@atlaskit/badge": "^18.2.0",
25
+ "@atlaskit/browser-apis": "^0.0.1",
25
26
  "@atlaskit/button": "^23.5.0",
26
27
  "@atlaskit/css": "^0.15.0",
27
28
  "@atlaskit/dropdown-menu": "^16.3.0",
@@ -32,9 +33,9 @@
32
33
  "@atlaskit/platform-feature-flags-react": "^0.3.0",
33
34
  "@atlaskit/popup": "^4.4.0",
34
35
  "@atlaskit/primitives": "^16.0.0",
35
- "@atlaskit/tmp-editor-statsig": "^13.13.0",
36
+ "@atlaskit/tmp-editor-statsig": "^13.18.0",
36
37
  "@atlaskit/tokens": "^7.0.0",
37
- "@atlaskit/tooltip": "^20.5.0",
38
+ "@atlaskit/tooltip": "^20.6.0",
38
39
  "@babel/runtime": "^7.0.0",
39
40
  "@compiled/react": "^0.18.6",
40
41
  "chromatism": "^2.6.0"
@@ -88,6 +89,9 @@
88
89
  "platform-feature-flags": {
89
90
  "platform_editor_ai_rovo_rebrand": {
90
91
  "type": "boolean"
92
+ },
93
+ "platform_editor_toolbar_aifc_patch_7": {
94
+ "type": "boolean"
91
95
  }
92
96
  }
93
97
  }