@atlaskit/jql-editor 5.0.8 → 5.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/jql-editor
2
2
 
3
+ ## 5.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#129443](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/129443)
8
+ [`cea97763ee228`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cea97763ee228) -
9
+ Pass down validation error messages and extra IDs for a11y [GRAVITYAI-2553]
10
+
3
11
  ## 5.0.8
4
12
 
5
13
  ### Patch Changes
@@ -6,5 +6,5 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useJqlEditorAnalytics = void 0;
7
7
  var _jqlEditorCommon = require("@atlaskit/jql-editor-common");
8
8
  var useJqlEditorAnalytics = exports.useJqlEditorAnalytics = function useJqlEditorAnalytics(analyticsSource) {
9
- return (0, _jqlEditorCommon.useJqlPackageAnalytics)(analyticsSource, "@atlaskit/jql-editor", "5.0.8", _jqlEditorCommon.ANALYTICS_CHANNEL);
9
+ return (0, _jqlEditorCommon.useJqlPackageAnalytics)(analyticsSource, "@atlaskit/jql-editor", "5.1.0", _jqlEditorCommon.ANALYTICS_CHANNEL);
10
10
  };
@@ -61,6 +61,65 @@ var useFormattedErrorMessage = function useFormattedErrorMessage() {
61
61
  }
62
62
  return null;
63
63
  };
64
+
65
+ /**
66
+ * This function maps client side validation errors and external messages into a unified format
67
+ * This is so that the output of this function can then be processed in a unified manner by different renderers
68
+ *
69
+ * ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
70
+ * Cloned from useFormattedErrorMessage. Differences are:
71
+ * - return type is ExternalMessage[] instead of ReactNode
72
+ * - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
73
+ */
74
+ var useErrorMessages = function useErrorMessages() {
75
+ var _useIntl3 = (0, _state.useIntl)(),
76
+ _useIntl4 = (0, _slicedToArray2.default)(_useIntl3, 1),
77
+ formatMessage = _useIntl4[0].formatMessage;
78
+ var _useJqlError3 = (0, _state.useJqlError)(),
79
+ _useJqlError4 = (0, _slicedToArray2.default)(_useJqlError3, 1),
80
+ jqlError = _useJqlError4[0];
81
+ var _useExternalMessages3 = (0, _state.useExternalMessages)(),
82
+ _useExternalMessages4 = (0, _slicedToArray2.default)(_useExternalMessages3, 1),
83
+ externalErrors = _useExternalMessages4[0].errors;
84
+ var _useStoreActions3 = (0, _state.useStoreActions)(),
85
+ _useStoreActions4 = (0, _slicedToArray2.default)(_useStoreActions3, 2),
86
+ externalErrorMessageViewed = _useStoreActions4[1].externalErrorMessageViewed;
87
+ var editorViewIsInvalid = (0, _useEditorViewIsInvalid.useEditorViewIsInvalid)();
88
+ (0, _react.useEffect)(function () {
89
+ // Emit a UI event whenever external errors has changed
90
+ externalErrorMessageViewed();
91
+ }, [externalErrorMessageViewed, externalErrors]);
92
+ if (!editorViewIsInvalid) {
93
+ return null;
94
+ }
95
+
96
+ /**
97
+ * Transform a string message to take the form of an ExternalMessage,
98
+ * so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
99
+ */
100
+ var toExternalMessageShape = function toExternalMessageShape(message) {
101
+ return [{
102
+ type: 'error',
103
+ message: message
104
+ }];
105
+ };
106
+
107
+ // Prioritise client errors over external errors
108
+ if (jqlError instanceof _jqlAst.JQLSyntaxError) {
109
+ return toExternalMessageShape("".concat(jqlError.message, " ").concat(formatMessage(_messages2.messages.jqlErrorPosition, {
110
+ lineNumber: jqlError.line,
111
+ charPosition: jqlError.charPositionInLine + 1
112
+ })));
113
+ }
114
+ if (externalErrors.length > 0) {
115
+ return externalErrors;
116
+ }
117
+ if (jqlError !== null) {
118
+ return toExternalMessageShape(formatMessage(_messages.commonMessages.unknownError));
119
+ }
120
+ return null;
121
+ };
122
+
64
123
  /**
65
124
  * This is a decorator component to include the editorTheme prop to the already passed list of props
66
125
  */
@@ -86,10 +145,41 @@ var ErrorMessages = exports.ErrorMessages = function ErrorMessages() {
86
145
  var _useScopedId3 = (0, _state.useScopedId)(_constants.JQL_EDITOR_VALIDATION_ID),
87
146
  _useScopedId4 = (0, _slicedToArray2.default)(_useScopedId3, 1),
88
147
  validationId = _useScopedId4[0];
89
- var errorMessage = useFormattedErrorMessage();
148
+ // eslint-disable-next-line react-hooks/rules-of-hooks
149
+ var errorMessages = (0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
150
+ var errorMessage = !(0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker') ?
151
+ // eslint-disable-next-line react-hooks/rules-of-hooks
152
+ useFormattedErrorMessage() : null;
90
153
  var _useCustomErrorCompon = (0, _state.useCustomErrorComponent)(),
91
154
  _useCustomErrorCompon2 = (0, _slicedToArray2.default)(_useCustomErrorCompon, 1),
92
155
  CustomErrorComponent = _useCustomErrorCompon2[0];
156
+ if ((0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker')) {
157
+ var _childrenToRender = errorMessages != null ? /*#__PURE__*/_react.default.createElement(_format.MessageContainer, null, /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, {
158
+ testId: _constants.JQL_EDITOR_VALIDATION_ID
159
+ }, (0, _platformFeatureFlags.fg)('jql_editor_a11y') ? /*#__PURE__*/_react.default.createElement("span", {
160
+ role: "alert",
161
+ id: validationId
162
+ }, /*#__PURE__*/_react.default.createElement(_format.FormatMessages, {
163
+ messages: errorMessages
164
+ })) : /*#__PURE__*/_react.default.createElement("span", {
165
+ role: "alert",
166
+ "aria-describedby": editorId
167
+ }, /*#__PURE__*/_react.default.createElement(_format.FormatMessages, {
168
+ messages: errorMessages
169
+ })))) : null;
170
+
171
+ // Only render CustomErrorComponent if there is an errorMessage
172
+ if (errorMessages != null && CustomErrorComponent) {
173
+ return /*#__PURE__*/_react.default.createElement(CustomComponentDecoratedWithEditorTheme, {
174
+ testId: _constants.JQL_EDITOR_VALIDATION_ID,
175
+ editorId: editorId,
176
+ validationId: validationId,
177
+ Component: CustomErrorComponent,
178
+ errorMessages: (0, _format.extractMessageNodes)(errorMessages)
179
+ }, _childrenToRender);
180
+ }
181
+ return _childrenToRender;
182
+ }
93
183
  var childrenToRender = errorMessage != null ? /*#__PURE__*/_react.default.createElement(_format.MessageContainer, null, /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, {
94
184
  testId: _constants.JQL_EDITOR_VALIDATION_ID
95
185
  }, (0, _platformFeatureFlags.fg)('jql_editor_a11y') ? /*#__PURE__*/_react.default.createElement("span", {
@@ -4,8 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.MessageContainer = exports.FormatMessages = void 0;
7
+ exports.extractMessageNodes = exports.MessageContainer = exports.FormatMessages = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
10
  var _useEditorTheme = require("../../../../hooks/use-editor-theme");
10
11
  var _styled = require("./styled");
11
12
  // Max number messages we want to show
@@ -20,6 +21,20 @@ var MessageContainer = exports.MessageContainer = function MessageContainer(_ref
20
21
  };
21
22
  var FormatMessages = exports.FormatMessages = function FormatMessages(_ref2) {
22
23
  var messages = _ref2.messages;
24
+ if ((0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker')) {
25
+ var messageNodes = extractMessageNodes(messages);
26
+ if (messageNodes.length === 0) {
27
+ return null;
28
+ }
29
+ if (messageNodes.length === 1) {
30
+ return /*#__PURE__*/_react.default.createElement("span", null, messageNodes[0]);
31
+ }
32
+ return /*#__PURE__*/_react.default.createElement(_styled.MessageList, null, messageNodes.map(function (m, i) {
33
+ return /*#__PURE__*/_react.default.createElement("li", {
34
+ key: i
35
+ }, m);
36
+ }));
37
+ }
23
38
  if (messages.length === 0) {
24
39
  return null;
25
40
  }
@@ -31,4 +46,16 @@ var FormatMessages = exports.FormatMessages = function FormatMessages(_ref2) {
31
46
  key: i
32
47
  }, m.message);
33
48
  }));
49
+ };
50
+
51
+ /**
52
+ * This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
53
+ * This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
54
+ *
55
+ * Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
56
+ */
57
+ var extractMessageNodes = exports.extractMessageNodes = function extractMessageNodes(messages) {
58
+ return messages.slice(0, MAX_MESSAGES).map(function (m) {
59
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, m.message);
60
+ });
34
61
  };
@@ -1,4 +1,4 @@
1
1
  import { ANALYTICS_CHANNEL, useJqlPackageAnalytics } from '@atlaskit/jql-editor-common';
2
2
  export const useJqlEditorAnalytics = analyticsSource => {
3
- return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.0.8", ANALYTICS_CHANNEL);
3
+ return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.1.0", ANALYTICS_CHANNEL);
4
4
  };
@@ -9,7 +9,7 @@ import { commonMessages } from '../../../../common/messages';
9
9
  import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
10
10
  import { useEditorViewIsInvalid } from '../../../../hooks/use-editor-view-is-invalid';
11
11
  import { useCustomErrorComponent, useExternalMessages, useIntl, useJqlError, useScopedId, useStoreActions } from '../../../../state';
12
- import { FormatMessages, MessageContainer } from '../format';
12
+ import { extractMessageNodes, FormatMessages, MessageContainer } from '../format';
13
13
  import { messages } from './messages';
14
14
  const useFormattedErrorMessage = () => {
15
15
  const [{
@@ -46,6 +46,61 @@ const useFormattedErrorMessage = () => {
46
46
  }
47
47
  return null;
48
48
  };
49
+
50
+ /**
51
+ * This function maps client side validation errors and external messages into a unified format
52
+ * This is so that the output of this function can then be processed in a unified manner by different renderers
53
+ *
54
+ * ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
55
+ * Cloned from useFormattedErrorMessage. Differences are:
56
+ * - return type is ExternalMessage[] instead of ReactNode
57
+ * - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
58
+ */
59
+ const useErrorMessages = () => {
60
+ const [{
61
+ formatMessage
62
+ }] = useIntl();
63
+ const [jqlError] = useJqlError();
64
+ const [{
65
+ errors: externalErrors
66
+ }] = useExternalMessages();
67
+ const [, {
68
+ externalErrorMessageViewed
69
+ }] = useStoreActions();
70
+ const editorViewIsInvalid = useEditorViewIsInvalid();
71
+ useEffect(() => {
72
+ // Emit a UI event whenever external errors has changed
73
+ externalErrorMessageViewed();
74
+ }, [externalErrorMessageViewed, externalErrors]);
75
+ if (!editorViewIsInvalid) {
76
+ return null;
77
+ }
78
+
79
+ /**
80
+ * Transform a string message to take the form of an ExternalMessage,
81
+ * so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
82
+ */
83
+ const toExternalMessageShape = message => [{
84
+ type: 'error',
85
+ message
86
+ }];
87
+
88
+ // Prioritise client errors over external errors
89
+ if (jqlError instanceof JQLSyntaxError) {
90
+ return toExternalMessageShape(`${jqlError.message} ${formatMessage(messages.jqlErrorPosition, {
91
+ lineNumber: jqlError.line,
92
+ charPosition: jqlError.charPositionInLine + 1
93
+ })}`);
94
+ }
95
+ if (externalErrors.length > 0) {
96
+ return externalErrors;
97
+ }
98
+ if (jqlError !== null) {
99
+ return toExternalMessageShape(formatMessage(commonMessages.unknownError));
100
+ }
101
+ return null;
102
+ };
103
+
49
104
  /**
50
105
  * This is a decorator component to include the editorTheme prop to the already passed list of props
51
106
  */
@@ -69,8 +124,39 @@ const CustomComponentDecoratedWithEditorTheme = props => {
69
124
  export const ErrorMessages = () => {
70
125
  const [editorId] = useScopedId(JQL_EDITOR_INPUT_ID);
71
126
  const [validationId] = useScopedId(JQL_EDITOR_VALIDATION_ID);
72
- const errorMessage = useFormattedErrorMessage();
127
+ // eslint-disable-next-line react-hooks/rules-of-hooks
128
+ const errorMessages = fg('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
129
+ const errorMessage = !fg('gravityai-2553-fix-jql-debugger-flicker') ?
130
+ // eslint-disable-next-line react-hooks/rules-of-hooks
131
+ useFormattedErrorMessage() : null;
73
132
  const [CustomErrorComponent] = useCustomErrorComponent();
133
+ if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
134
+ const childrenToRender = errorMessages != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
135
+ testId: JQL_EDITOR_VALIDATION_ID
136
+ }, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
137
+ role: "alert",
138
+ id: validationId
139
+ }, /*#__PURE__*/React.createElement(FormatMessages, {
140
+ messages: errorMessages
141
+ })) : /*#__PURE__*/React.createElement("span", {
142
+ role: "alert",
143
+ "aria-describedby": editorId
144
+ }, /*#__PURE__*/React.createElement(FormatMessages, {
145
+ messages: errorMessages
146
+ })))) : null;
147
+
148
+ // Only render CustomErrorComponent if there is an errorMessage
149
+ if (errorMessages != null && CustomErrorComponent) {
150
+ return /*#__PURE__*/React.createElement(CustomComponentDecoratedWithEditorTheme, {
151
+ testId: JQL_EDITOR_VALIDATION_ID,
152
+ editorId: editorId,
153
+ validationId: validationId,
154
+ Component: CustomErrorComponent,
155
+ errorMessages: extractMessageNodes(errorMessages)
156
+ }, childrenToRender);
157
+ }
158
+ return childrenToRender;
159
+ }
74
160
  const childrenToRender = errorMessage != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
75
161
  testId: JQL_EDITOR_VALIDATION_ID
76
162
  }, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
3
4
  import { MessageContainer as MessageContainerStyled, MessageList } from './styled';
4
5
 
@@ -17,6 +18,18 @@ export const MessageContainer = ({
17
18
  export const FormatMessages = ({
18
19
  messages
19
20
  }) => {
21
+ if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
22
+ const messageNodes = extractMessageNodes(messages);
23
+ if (messageNodes.length === 0) {
24
+ return null;
25
+ }
26
+ if (messageNodes.length === 1) {
27
+ return /*#__PURE__*/React.createElement("span", null, messageNodes[0]);
28
+ }
29
+ return /*#__PURE__*/React.createElement(MessageList, null, messageNodes.map((m, i) => /*#__PURE__*/React.createElement("li", {
30
+ key: i
31
+ }, m)));
32
+ }
20
33
  if (messages.length === 0) {
21
34
  return null;
22
35
  }
@@ -26,4 +39,14 @@ export const FormatMessages = ({
26
39
  return /*#__PURE__*/React.createElement(MessageList, null, messages.slice(0, MAX_MESSAGES).map((m, i) => /*#__PURE__*/React.createElement("li", {
27
40
  key: i
28
41
  }, m.message)));
42
+ };
43
+
44
+ /**
45
+ * This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
46
+ * This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
47
+ *
48
+ * Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
49
+ */
50
+ export const extractMessageNodes = messages => {
51
+ return messages.slice(0, MAX_MESSAGES).map(m => /*#__PURE__*/React.createElement(React.Fragment, null, m.message));
29
52
  };
@@ -1,4 +1,4 @@
1
1
  import { ANALYTICS_CHANNEL, useJqlPackageAnalytics } from '@atlaskit/jql-editor-common';
2
2
  export var useJqlEditorAnalytics = function useJqlEditorAnalytics(analyticsSource) {
3
- return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.0.8", ANALYTICS_CHANNEL);
3
+ return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.1.0", ANALYTICS_CHANNEL);
4
4
  };
@@ -12,7 +12,7 @@ import { commonMessages } from '../../../../common/messages';
12
12
  import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
13
13
  import { useEditorViewIsInvalid } from '../../../../hooks/use-editor-view-is-invalid';
14
14
  import { useCustomErrorComponent, useExternalMessages, useIntl, useJqlError, useScopedId, useStoreActions } from '../../../../state';
15
- import { FormatMessages, MessageContainer } from '../format';
15
+ import { extractMessageNodes, FormatMessages, MessageContainer } from '../format';
16
16
  import { messages } from './messages';
17
17
  var useFormattedErrorMessage = function useFormattedErrorMessage() {
18
18
  var _useIntl = useIntl(),
@@ -51,6 +51,65 @@ var useFormattedErrorMessage = function useFormattedErrorMessage() {
51
51
  }
52
52
  return null;
53
53
  };
54
+
55
+ /**
56
+ * This function maps client side validation errors and external messages into a unified format
57
+ * This is so that the output of this function can then be processed in a unified manner by different renderers
58
+ *
59
+ * ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
60
+ * Cloned from useFormattedErrorMessage. Differences are:
61
+ * - return type is ExternalMessage[] instead of ReactNode
62
+ * - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
63
+ */
64
+ var useErrorMessages = function useErrorMessages() {
65
+ var _useIntl3 = useIntl(),
66
+ _useIntl4 = _slicedToArray(_useIntl3, 1),
67
+ formatMessage = _useIntl4[0].formatMessage;
68
+ var _useJqlError3 = useJqlError(),
69
+ _useJqlError4 = _slicedToArray(_useJqlError3, 1),
70
+ jqlError = _useJqlError4[0];
71
+ var _useExternalMessages3 = useExternalMessages(),
72
+ _useExternalMessages4 = _slicedToArray(_useExternalMessages3, 1),
73
+ externalErrors = _useExternalMessages4[0].errors;
74
+ var _useStoreActions3 = useStoreActions(),
75
+ _useStoreActions4 = _slicedToArray(_useStoreActions3, 2),
76
+ externalErrorMessageViewed = _useStoreActions4[1].externalErrorMessageViewed;
77
+ var editorViewIsInvalid = useEditorViewIsInvalid();
78
+ useEffect(function () {
79
+ // Emit a UI event whenever external errors has changed
80
+ externalErrorMessageViewed();
81
+ }, [externalErrorMessageViewed, externalErrors]);
82
+ if (!editorViewIsInvalid) {
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Transform a string message to take the form of an ExternalMessage,
88
+ * so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
89
+ */
90
+ var toExternalMessageShape = function toExternalMessageShape(message) {
91
+ return [{
92
+ type: 'error',
93
+ message: message
94
+ }];
95
+ };
96
+
97
+ // Prioritise client errors over external errors
98
+ if (jqlError instanceof JQLSyntaxError) {
99
+ return toExternalMessageShape("".concat(jqlError.message, " ").concat(formatMessage(messages.jqlErrorPosition, {
100
+ lineNumber: jqlError.line,
101
+ charPosition: jqlError.charPositionInLine + 1
102
+ })));
103
+ }
104
+ if (externalErrors.length > 0) {
105
+ return externalErrors;
106
+ }
107
+ if (jqlError !== null) {
108
+ return toExternalMessageShape(formatMessage(commonMessages.unknownError));
109
+ }
110
+ return null;
111
+ };
112
+
54
113
  /**
55
114
  * This is a decorator component to include the editorTheme prop to the already passed list of props
56
115
  */
@@ -76,10 +135,41 @@ export var ErrorMessages = function ErrorMessages() {
76
135
  var _useScopedId3 = useScopedId(JQL_EDITOR_VALIDATION_ID),
77
136
  _useScopedId4 = _slicedToArray(_useScopedId3, 1),
78
137
  validationId = _useScopedId4[0];
79
- var errorMessage = useFormattedErrorMessage();
138
+ // eslint-disable-next-line react-hooks/rules-of-hooks
139
+ var errorMessages = fg('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
140
+ var errorMessage = !fg('gravityai-2553-fix-jql-debugger-flicker') ?
141
+ // eslint-disable-next-line react-hooks/rules-of-hooks
142
+ useFormattedErrorMessage() : null;
80
143
  var _useCustomErrorCompon = useCustomErrorComponent(),
81
144
  _useCustomErrorCompon2 = _slicedToArray(_useCustomErrorCompon, 1),
82
145
  CustomErrorComponent = _useCustomErrorCompon2[0];
146
+ if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
147
+ var _childrenToRender = errorMessages != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
148
+ testId: JQL_EDITOR_VALIDATION_ID
149
+ }, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
150
+ role: "alert",
151
+ id: validationId
152
+ }, /*#__PURE__*/React.createElement(FormatMessages, {
153
+ messages: errorMessages
154
+ })) : /*#__PURE__*/React.createElement("span", {
155
+ role: "alert",
156
+ "aria-describedby": editorId
157
+ }, /*#__PURE__*/React.createElement(FormatMessages, {
158
+ messages: errorMessages
159
+ })))) : null;
160
+
161
+ // Only render CustomErrorComponent if there is an errorMessage
162
+ if (errorMessages != null && CustomErrorComponent) {
163
+ return /*#__PURE__*/React.createElement(CustomComponentDecoratedWithEditorTheme, {
164
+ testId: JQL_EDITOR_VALIDATION_ID,
165
+ editorId: editorId,
166
+ validationId: validationId,
167
+ Component: CustomErrorComponent,
168
+ errorMessages: extractMessageNodes(errorMessages)
169
+ }, _childrenToRender);
170
+ }
171
+ return _childrenToRender;
172
+ }
83
173
  var childrenToRender = errorMessage != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
84
174
  testId: JQL_EDITOR_VALIDATION_ID
85
175
  }, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
3
4
  import { MessageContainer as MessageContainerStyled, MessageList } from './styled';
4
5
 
@@ -14,6 +15,20 @@ export var MessageContainer = function MessageContainer(_ref) {
14
15
  };
15
16
  export var FormatMessages = function FormatMessages(_ref2) {
16
17
  var messages = _ref2.messages;
18
+ if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
19
+ var messageNodes = extractMessageNodes(messages);
20
+ if (messageNodes.length === 0) {
21
+ return null;
22
+ }
23
+ if (messageNodes.length === 1) {
24
+ return /*#__PURE__*/React.createElement("span", null, messageNodes[0]);
25
+ }
26
+ return /*#__PURE__*/React.createElement(MessageList, null, messageNodes.map(function (m, i) {
27
+ return /*#__PURE__*/React.createElement("li", {
28
+ key: i
29
+ }, m);
30
+ }));
31
+ }
17
32
  if (messages.length === 0) {
18
33
  return null;
19
34
  }
@@ -25,4 +40,16 @@ export var FormatMessages = function FormatMessages(_ref2) {
25
40
  key: i
26
41
  }, m.message);
27
42
  }));
43
+ };
44
+
45
+ /**
46
+ * This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
47
+ * This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
48
+ *
49
+ * Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
50
+ */
51
+ export var extractMessageNodes = function extractMessageNodes(messages) {
52
+ return messages.slice(0, MAX_MESSAGES).map(function (m) {
53
+ return /*#__PURE__*/React.createElement(React.Fragment, null, m.message);
54
+ });
28
55
  };
@@ -69,7 +69,12 @@ export type CustomErrorComponent = React.ComponentType<PropsWithChildren<{
69
69
  testId: string;
70
70
  editorTheme: EditorTheme;
71
71
  editorId: string;
72
+ errorMessages?: React.ReactElement[];
73
+ validationId?: string;
72
74
  }>>;
75
+ export type CustomErrorMessageProps = Omit<React.ComponentProps<CustomErrorComponent>, 'editorTheme'> & {
76
+ Component: CustomErrorComponent;
77
+ };
73
78
  export type CustomComponents = {
74
79
  ErrorMessage?: CustomErrorComponent;
75
80
  };
@@ -6,3 +6,10 @@ export declare const MessageContainer: ({ children }: {
6
6
  export declare const FormatMessages: ({ messages }: {
7
7
  messages: ExternalMessage[];
8
8
  }) => React.JSX.Element | null;
9
+ /**
10
+ * This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
11
+ * This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
12
+ *
13
+ * Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
14
+ */
15
+ export declare const extractMessageNodes: (messages: ExternalMessage[]) => React.ReactElement[];
@@ -69,7 +69,12 @@ export type CustomErrorComponent = React.ComponentType<PropsWithChildren<{
69
69
  testId: string;
70
70
  editorTheme: EditorTheme;
71
71
  editorId: string;
72
+ errorMessages?: React.ReactElement[];
73
+ validationId?: string;
72
74
  }>>;
75
+ export type CustomErrorMessageProps = Omit<React.ComponentProps<CustomErrorComponent>, 'editorTheme'> & {
76
+ Component: CustomErrorComponent;
77
+ };
73
78
  export type CustomComponents = {
74
79
  ErrorMessage?: CustomErrorComponent;
75
80
  };
@@ -6,3 +6,10 @@ export declare const MessageContainer: ({ children }: {
6
6
  export declare const FormatMessages: ({ messages }: {
7
7
  messages: ExternalMessage[];
8
8
  }) => React.JSX.Element | null;
9
+ /**
10
+ * This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
11
+ * This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
12
+ *
13
+ * Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
14
+ */
15
+ export declare const extractMessageNodes: (messages: ExternalMessage[]) => React.ReactElement[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/jql-editor",
3
- "version": "5.0.8",
3
+ "version": "5.1.0",
4
4
  "description": "This package allows consumers to render an advanced JQL editor component to enable autocomplete-assisted authoring and validation of JQL queries.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -136,6 +136,9 @@
136
136
  },
137
137
  "jql_editor_a11y": {
138
138
  "type": "boolean"
139
+ },
140
+ "gravityai-2553-fix-jql-debugger-flicker": {
141
+ "type": "boolean"
139
142
  }
140
143
  }
141
144
  }