@atlaskit/renderer 126.3.0 → 126.5.0

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.
@@ -56,7 +56,7 @@ export const DEGRADED_SEVERITY_THRESHOLD = 3000;
56
56
  const TABLE_INFO_TIMEOUT = 10000;
57
57
  const RENDER_EVENT_SAMPLE_RATE = 0.2;
58
58
  const packageName = "@atlaskit/renderer";
59
- const packageVersion = "0.0.0-development";
59
+ const packageVersion = "126.4.0";
60
60
  const setAsQueryContainerStyles = css({
61
61
  containerName: 'ak-renderer-wrapper',
62
62
  containerType: 'inline-size'
@@ -8,6 +8,16 @@ export var headingAnchorLinkMessages = defineMessages({
8
8
  defaultMessage: 'Copy link to heading',
9
9
  description: 'Copy heading link to clipboard'
10
10
  },
11
+ copyLinkToClipboard: {
12
+ id: 'fabric.editor.headingLink.copyAnchorLinkTo',
13
+ defaultMessage: 'Copy link to',
14
+ description: 'Copy heading link to clipboard. Will be used as part of a 2-part a11y label ("Copy link to", "{heading text}")'
15
+ },
16
+ copyHeadingLinkLabelledBy: {
17
+ id: 'fabric.editor.headingLink.copyAnchorLinkLabelledBy',
18
+ defaultMessage: '{copyLink} {heading}',
19
+ description: 'The order in which to read the parts of the aria-labelledby for the copy heading link button depending on the grammar of the language. {copyLink} will be replaced with the "Copy link to" text and {heading} will be replaced with the actual heading text'
20
+ },
11
21
  copiedHeadingLinkToClipboard: {
12
22
  id: 'fabric.editor.headingLink.copied',
13
23
  defaultMessage: 'Copied!',
@@ -21,6 +21,7 @@ import React from 'react';
21
21
  import { css, jsx } from '@emotion/react';
22
22
  import { injectIntl } from 'react-intl-next';
23
23
  import LinkIcon from '@atlaskit/icon/core/link';
24
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
24
25
  import Tooltip from '@atlaskit/tooltip';
25
26
  import { headingAnchorLinkMessages } from '../../messages';
26
27
  export var HeadingAnchorWrapperClassName = 'heading-anchor-wrapper';
@@ -45,13 +46,10 @@ var copyAnchorButtonStyles = css({
45
46
  // Ignored via go/ees005
46
47
  // eslint-disable-next-line @repo/internal/react/no-class-components
47
48
  var HeadingAnchor = /*#__PURE__*/function (_React$PureComponent) {
48
- function HeadingAnchor() {
49
+ function HeadingAnchor(props) {
49
50
  var _this;
50
51
  _classCallCheck(this, HeadingAnchor);
51
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
52
- args[_key] = arguments[_key];
53
- }
54
- _this = _callSuper(this, HeadingAnchor, [].concat(args));
52
+ _this = _callSuper(this, HeadingAnchor, [props]);
55
53
  _defineProperty(_this, "state", {
56
54
  tooltipMessage: '',
57
55
  isClicked: false
@@ -98,30 +96,38 @@ var HeadingAnchor = /*#__PURE__*/function (_React$PureComponent) {
98
96
  };
99
97
  }());
100
98
  _defineProperty(_this, "resetMessage", function () {
101
- _this.setTooltipState(headingAnchorLinkMessages.copyHeadingLinkToClipboard);
99
+ var tooltip = expValEquals('platform_editor_copy_link_a11y_inconsistency_fix', 'isEnabled', true) ? headingAnchorLinkMessages.copyLinkToClipboard : headingAnchorLinkMessages.copyHeadingLinkToClipboard;
100
+ _this.setTooltipState(tooltip);
102
101
  });
103
102
  _defineProperty(_this, "renderAnchorButton", function () {
104
103
  var _this$props = _this.props,
105
104
  _this$props$hideFromS = _this$props.hideFromScreenReader,
106
105
  hideFromScreenReader = _this$props$hideFromS === void 0 ? false : _this$props$hideFromS,
107
106
  headingId = _this$props.headingId;
107
+ var labelledBy = expValEquals('platform_editor_copy_link_a11y_inconsistency_fix', 'isEnabled', true) ? _this.props.intl.formatMessage(headingAnchorLinkMessages.copyHeadingLinkLabelledBy, {
108
+ copyLink: _this.copyLinkId,
109
+ heading: headingId
110
+ }) : headingId;
111
+ var tabIndex = expValEquals('platform_editor_copy_link_a11y_inconsistency_fix', 'isEnabled', true) ? 0 : hideFromScreenReader ? undefined : -1;
108
112
  return jsx("button", {
109
113
  "data-testid": "anchor-button",
114
+ id: _this.copyLinkId,
110
115
  css: copyAnchorButtonStyles
111
116
  // eslint-disable-next-line @atlassian/a11y/mouse-events-have-key-events
112
117
  ,
113
118
  onMouseLeave: _this.resetMessage,
114
119
  onClick: _this.copyToClipboard,
115
120
  "aria-hidden": hideFromScreenReader,
116
- tabIndex: hideFromScreenReader ? undefined : -1,
121
+ tabIndex: tabIndex,
117
122
  "aria-label": hideFromScreenReader ? undefined : _this.state.tooltipMessage,
118
- "aria-labelledby": hideFromScreenReader ? undefined : headingId,
123
+ "aria-labelledby": hideFromScreenReader ? undefined : labelledBy,
119
124
  type: "button"
120
125
  }, jsx(LinkIcon, {
121
126
  label: _this.getCopyAriaLabel(),
122
127
  color: _this.state.isClicked ? "var(--ds-icon-selected, #1868DB)" : "var(--ds-icon-subtle, #505258)"
123
128
  }));
124
129
  });
130
+ _this.copyLinkId = expValEquals('platform_editor_copy_link_a11y_inconsistency_fix', 'isEnabled', true) ? crypto.randomUUID() : undefined;
125
131
  return _this;
126
132
  }
127
133
  _inherits(HeadingAnchor, _React$PureComponent);
@@ -1,10 +1,18 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ * @jsxFrag
5
+ */
1
6
  import React from 'react';
2
- import VisuallyHidden from '@atlaskit/visually-hidden';
3
7
  import { abortAll } from '@atlaskit/react-ufo/interaction-metrics';
4
8
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
9
+ import VisuallyHidden from '@atlaskit/visually-hidden';
10
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
11
  import AnalyticsContext from '../../analytics/analyticsContext';
6
12
  import { copyTextToClipboard } from '../utils/clipboard';
7
13
  import HeadingAnchor from './heading-anchor';
14
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
15
+ import { css, jsx } from '@emotion/react';
8
16
  var getCurrentUrlWithHash = function getCurrentUrlWithHash() {
9
17
  var hash = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
10
18
  var url = new URL(window.location.href);
@@ -20,14 +28,18 @@ function hasRightAlignmentMark(marks) {
20
28
  return mark.type.name === 'alignment' && mark.attrs.align === 'end';
21
29
  });
22
30
  }
31
+ var wrapperStyles = css({
32
+ display: 'flex',
33
+ alignItems: 'baseline'
34
+ });
23
35
  function WrappedHeadingAnchor(_ref) {
24
36
  var enableNestedHeaderLinks = _ref.enableNestedHeaderLinks,
25
37
  level = _ref.level,
26
38
  headingId = _ref.headingId,
27
39
  hideFromScreenReader = _ref.hideFromScreenReader;
28
- return /*#__PURE__*/React.createElement(AnalyticsContext.Consumer, null, function (_ref2) {
40
+ return jsx(AnalyticsContext.Consumer, null, function (_ref2) {
29
41
  var fireAnalyticsEvent = _ref2.fireAnalyticsEvent;
30
- return /*#__PURE__*/React.createElement(HeadingAnchor, {
42
+ return jsx(HeadingAnchor, {
31
43
  enableNestedHeaderLinks: enableNestedHeaderLinks,
32
44
  level: level,
33
45
  onCopyText: function onCopyText() {
@@ -44,7 +56,14 @@ function WrappedHeadingAnchor(_ref) {
44
56
  });
45
57
  });
46
58
  }
47
- function Heading(props) {
59
+ /**
60
+ * Old heading structure (before a11y fix):
61
+ * - headning anchor is rendered INSIDE the heading element
62
+ * - A duplicate anchor is rendered in VisuallyHidden for screen readers
63
+ * - The visible button has hideFromScreenReader={true}
64
+ *
65
+ */
66
+ function HeadingWithDuplicateAnchor(props) {
48
67
  var headingId = props.headingId,
49
68
  dataAttributes = props.dataAttributes,
50
69
  allowHeadingAnchorLinks = props.allowHeadingAnchorLinks,
@@ -67,28 +86,132 @@ function Heading(props) {
67
86
  mouseEntered.current = true;
68
87
  }
69
88
  };
70
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(HX, {
89
+ return jsx(React.Fragment, null, jsx(HX, {
71
90
  id: headingIdToUse,
72
91
  "data-local-id": localId,
73
92
  "data-renderer-start-pos": dataAttributes['data-renderer-start-pos'],
74
93
  "data-as-inline": asInline,
75
94
  onMouseEnter: mouseEnterHandler
76
- }, /*#__PURE__*/React.createElement(React.Fragment, null, showAnchorLink && headingId && isRightAligned && /*#__PURE__*/React.createElement(WrappedHeadingAnchor, {
95
+ }, jsx(React.Fragment, null, showAnchorLink && headingId && isRightAligned && jsx(WrappedHeadingAnchor, {
77
96
  level: props.level,
78
97
  enableNestedHeaderLinks: enableNestedHeaderLinks,
79
98
  headingId: headingId,
80
99
  hideFromScreenReader: true
81
- }), props.children, showAnchorLink && headingId && !isRightAligned && /*#__PURE__*/React.createElement(WrappedHeadingAnchor, {
100
+ }), props.children, showAnchorLink && headingId && !isRightAligned && jsx(WrappedHeadingAnchor, {
82
101
  level: props.level,
83
102
  enableNestedHeaderLinks: enableNestedHeaderLinks,
84
103
  headingId: headingId,
85
104
  hideFromScreenReader: true
86
- }))), /*#__PURE__*/React.createElement(VisuallyHidden, {
105
+ }))), jsx(VisuallyHidden, {
87
106
  testId: "visually-hidden-heading-anchor"
88
- }, showAnchorLink && headingId && /*#__PURE__*/React.createElement(WrappedHeadingAnchor, {
107
+ }, showAnchorLink && headingId && jsx(WrappedHeadingAnchor, {
89
108
  level: props.level,
90
109
  enableNestedHeaderLinks: enableNestedHeaderLinks,
91
110
  headingId: headingId
92
111
  })));
93
112
  }
113
+
114
+ /**
115
+ * New heading structure (a11y fix):
116
+ * - Heading anchor is rendered OUTSIDE the heading element in a .renderer-heading-wrapper div
117
+ * - Uses data-level attribute for CSS styling
118
+ * - Better accessibility: heading contains only text, button is a sibling
119
+ */
120
+ function HeadingWithWrapper(props) {
121
+ var headingId = props.headingId,
122
+ dataAttributes = props.dataAttributes,
123
+ allowHeadingAnchorLinks = props.allowHeadingAnchorLinks,
124
+ marks = props.marks,
125
+ invisible = props.invisible,
126
+ localId = props.localId,
127
+ asInline = props.asInline;
128
+ var HX = "h".concat(props.level);
129
+ var mouseEntered = React.useRef(false);
130
+ var showAnchorLink = !!props.showAnchorLink;
131
+ var isRightAligned = hasRightAlignmentMark(marks);
132
+ var enableNestedHeaderLinks = allowHeadingAnchorLinks && allowHeadingAnchorLinks.allowNestedHeaderLinks;
133
+ var headingIdToUse = invisible ? undefined : headingId;
134
+ var mouseEnterHandler = function mouseEnterHandler() {
135
+ if (showAnchorLink && !mouseEntered.current) {
136
+ // Abort TTVC calculation when the mouse hovers over heading. Hovering over
137
+ // heading render heading anchor and inline comment buttons. These user-induced
138
+ // DOM changes are valid reasons to abort the TTVC calculation.
139
+ abortAll('new_interaction');
140
+ mouseEntered.current = true;
141
+ }
142
+ };
143
+ return (
144
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
145
+ jsx("div", {
146
+ className: "renderer-heading-wrapper",
147
+ "data-level": props.level,
148
+ css: wrapperStyles
149
+ }, showAnchorLink && headingId && isRightAligned && jsx(WrappedHeadingAnchor, {
150
+ level: props.level,
151
+ enableNestedHeaderLinks: enableNestedHeaderLinks,
152
+ headingId: headingId,
153
+ hideFromScreenReader: false
154
+ }), jsx(HX, {
155
+ id: headingIdToUse,
156
+ "data-local-id": localId,
157
+ "data-renderer-start-pos": dataAttributes['data-renderer-start-pos'],
158
+ "data-as-inline": asInline,
159
+ onMouseEnter: mouseEnterHandler
160
+ }, props.children), showAnchorLink && headingId && !isRightAligned && jsx(WrappedHeadingAnchor, {
161
+ level: props.level,
162
+ enableNestedHeaderLinks: enableNestedHeaderLinks,
163
+ headingId: headingId,
164
+ hideFromScreenReader: false
165
+ }))
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Gated Heading component:
171
+ * - When platform_editor_copy_link_a11y_inconsistency_fix experiment is enabled,
172
+ * returns HeadingWithWrapper (new a11y-improved structure)
173
+ * - Otherwise returns HeadingWithDuplicateAnchor (old structure)
174
+ */
175
+ function Heading(_ref3) {
176
+ var allowHeadingAnchorLinks = _ref3.allowHeadingAnchorLinks,
177
+ children = _ref3.children,
178
+ dataAttributes = _ref3.dataAttributes,
179
+ headingId = _ref3.headingId,
180
+ invisible = _ref3.invisible,
181
+ level = _ref3.level,
182
+ localId = _ref3.localId,
183
+ marks = _ref3.marks,
184
+ nodeType = _ref3.nodeType,
185
+ showAnchorLink = _ref3.showAnchorLink,
186
+ serializer = _ref3.serializer,
187
+ asInline = _ref3.asInline;
188
+ if (expValEquals('platform_editor_copy_link_a11y_inconsistency_fix', 'isEnabled', true)) {
189
+ return jsx(HeadingWithWrapper, {
190
+ allowHeadingAnchorLinks: allowHeadingAnchorLinks,
191
+ dataAttributes: dataAttributes,
192
+ headingId: headingId,
193
+ invisible: invisible,
194
+ level: level,
195
+ localId: localId,
196
+ marks: marks,
197
+ nodeType: nodeType,
198
+ serializer: serializer,
199
+ showAnchorLink: showAnchorLink,
200
+ asInline: asInline
201
+ }, children);
202
+ }
203
+ return jsx(HeadingWithDuplicateAnchor, {
204
+ allowHeadingAnchorLinks: allowHeadingAnchorLinks,
205
+ dataAttributes: dataAttributes,
206
+ headingId: headingId,
207
+ invisible: invisible,
208
+ level: level,
209
+ localId: localId,
210
+ marks: marks,
211
+ nodeType: nodeType,
212
+ serializer: serializer,
213
+ showAnchorLink: showAnchorLink,
214
+ asInline: asInline
215
+ }, children);
216
+ }
94
217
  export default Heading;