@atlaskit/editor-common 110.49.2 → 110.50.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,17 @@
1
1
  # @atlaskit/editor-common
2
2
 
3
+ ## 110.50.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`909bd527e4564`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/909bd527e4564) -
8
+ Introduce a new createADFFromHTML function for use with the placeholder options.
9
+
10
+ ### Patch Changes
11
+
12
+ - [`fd5c8dd25d59a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fd5c8dd25d59a) -
13
+ [ux] [ENGHEALTH-47470] remove redundant aria-label from ErrorIcon
14
+
3
15
  ## 110.49.2
4
16
 
5
17
  ### Patch Changes
@@ -451,5 +451,15 @@ var _default = exports.default = (0, _reactIntlNext.defineMessages)({
451
451
  id: 'fabric.editor.imageEdit',
452
452
  defaultMessage: 'Edit image',
453
453
  description: 'Crop, flip or rotate the image'
454
+ },
455
+ error: {
456
+ id: 'fabric.editor.error.message.label',
457
+ defaultMessage: 'Error',
458
+ description: 'Label for error message icon'
459
+ },
460
+ success: {
461
+ id: 'fabric.editor.success.message.label',
462
+ defaultMessage: 'Success',
463
+ description: 'Label for success message icon'
454
464
  }
455
465
  });
@@ -19,7 +19,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
19
19
  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); }
20
20
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
21
21
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
22
- var packageVersion = "110.49.1";
22
+ var packageVersion = "110.49.2";
23
23
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
24
24
  // Remove URL as it has UGC
25
25
  // Ignored via go/ees007
@@ -24,7 +24,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
24
24
  * @jsx jsx
25
25
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
26
26
  var packageName = "@atlaskit/editor-common";
27
- var packageVersion = "110.49.1";
27
+ var packageVersion = "110.49.2";
28
28
  var halfFocusRing = 1;
29
29
  var dropOffset = '0, 8';
30
30
  var fadeIn = (0, _react2.keyframes)({
@@ -6,8 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.ValidMessage = exports.HelperMessage = exports.ErrorMessage = void 0;
8
8
  var _react = require("@emotion/react");
9
+ var _reactIntlNext = require("react-intl-next");
9
10
  var _statusError = _interopRequireDefault(require("@atlaskit/icon/core/status-error"));
10
11
  var _statusSuccess = _interopRequireDefault(require("@atlaskit/icon/core/status-success"));
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
+ var _messages = _interopRequireDefault(require("../../messages"));
11
14
  /**
12
15
  * @jsxRuntime classic
13
16
  * @jsx jsx
@@ -52,13 +55,18 @@ var HelperMessage = exports.HelperMessage = function HelperMessage(_ref) {
52
55
  };
53
56
  var ErrorMessage = exports.ErrorMessage = function ErrorMessage(_ref2) {
54
57
  var children = _ref2.children;
58
+ var intl = (0, _reactIntlNext.useIntl)();
55
59
  return (0, _react.jsx)("div", {
56
60
  css: function css() {
57
61
  return [messageStyle(), errorColor];
58
62
  }
59
63
  }, (0, _react.jsx)("span", {
60
64
  css: iconWrapperStyle
61
- }, (0, _react.jsx)(_statusError.default, {
65
+ }, (0, _platformFeatureFlags.fg)('platform_editor_dec_a11y_fixes') ? (0, _react.jsx)(_statusError.default, {
66
+ LEGACY_size: "small",
67
+ label: intl.formatMessage(_messages.default.error)
68
+ })
69
+ /* eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx */ : (0, _react.jsx)(_statusError.default, {
62
70
  LEGACY_size: "small",
63
71
  label: "error",
64
72
  "aria-label": "error"
@@ -66,13 +74,17 @@ var ErrorMessage = exports.ErrorMessage = function ErrorMessage(_ref2) {
66
74
  };
67
75
  var ValidMessage = exports.ValidMessage = function ValidMessage(_ref3) {
68
76
  var children = _ref3.children;
77
+ var intl = (0, _reactIntlNext.useIntl)();
69
78
  return (0, _react.jsx)("div", {
70
79
  css: function css() {
71
80
  return [messageStyle(), validColor];
72
81
  }
73
82
  }, (0, _react.jsx)("span", {
74
83
  css: iconWrapperStyle
75
- }, (0, _react.jsx)(_statusSuccess.default, {
84
+ }, (0, _platformFeatureFlags.fg)('platform_editor_dec_a11y_fixes') ? (0, _react.jsx)(_statusSuccess.default, {
85
+ LEGACY_size: "small",
86
+ label: intl.formatMessage(_messages.default.success)
87
+ }) : (0, _react.jsx)(_statusSuccess.default, {
76
88
  LEGACY_size: "small",
77
89
  label: "success"
78
90
  })), children);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createADFFromHTML = void 0;
7
+ var _parseHtmlTextContent = require("./parse-html-text-content");
8
+ /**
9
+ * Creates ADF from HTML string.
10
+ * This is particularly useful for providing translations in HTML to be supported and we convert back to ADF here
11
+ * See: https://developer.atlassian.com/platform/localization/i18n-formatting/avoiding-concatenation/
12
+ *
13
+ * This function only supports a subset of the schema as it is intended for translations, but it supports
14
+ * SSR as it has no DOM dependencies and is lightweight.
15
+ *
16
+ * @param html - The HTML string to convert to ADF
17
+ * @returns ADF DocNode or undefined if parsing fails
18
+ */
19
+ var createADFFromHTML = exports.createADFFromHTML = function createADFFromHTML(html) {
20
+ return (0, _parseHtmlTextContent.parseHTMLTextContent)(html);
21
+ };
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.parseHTMLTextContent = exports.getNestingRulesFromSchema = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _schemaDefault = require("@atlaskit/adf-schema/schema-default");
11
+ var _model = require("@atlaskit/editor-prosemirror/model");
12
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
15
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
16
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
17
+ var domParser = _model.DOMParser.fromSchema(_schemaDefault.defaultSchema);
18
+ var getNestingRulesFromSchema = exports.getNestingRulesFromSchema = function getNestingRulesFromSchema() {
19
+ var KEYWORDS = ['inline', 'block', 'text', 'leaf', 'group', 'unsupportedBlock', 'unsupportedInline'];
20
+ var rules = {};
21
+ for (var _i = 0, _Object$keys = Object.keys(_schemaDefault.defaultSchema.nodes); _i < _Object$keys.length; _i++) {
22
+ var _defaultSchema$nodes$;
23
+ var nodeType = _Object$keys[_i];
24
+ var contentStr = (_defaultSchema$nodes$ = _schemaDefault.defaultSchema.nodes[nodeType]) === null || _defaultSchema$nodes$ === void 0 ? void 0 : _defaultSchema$nodes$.spec.content;
25
+ if (!contentStr) {
26
+ continue;
27
+ }
28
+ var allowedChildren =
29
+ // eslint-disable-next-line require-unicode-regexp
30
+ (String(contentStr).match(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g) || []).filter(function (match, index, arr) {
31
+ return !KEYWORDS.includes(match) && _schemaDefault.defaultSchema.nodes[match] && arr.indexOf(match) === index;
32
+ });
33
+ if (allowedChildren.length > 0) {
34
+ rules[nodeType] = allowedChildren;
35
+ }
36
+ }
37
+ return rules;
38
+ };
39
+ var NESTING_RULES = getNestingRulesFromSchema();
40
+ var canContainChildren = function canContainChildren(nodeType) {
41
+ var _NESTING_RULES$nodeTy;
42
+ return !!((_NESTING_RULES$nodeTy = NESTING_RULES[nodeType]) !== null && _NESTING_RULES$nodeTy !== void 0 && _NESTING_RULES$nodeTy.length);
43
+ };
44
+ var isAllowedChild = function isAllowedChild(parent, child) {
45
+ var _NESTING_RULES$parent, _NESTING_RULES$parent2;
46
+ return (_NESTING_RULES$parent = (_NESTING_RULES$parent2 = NESTING_RULES[parent]) === null || _NESTING_RULES$parent2 === void 0 ? void 0 : _NESTING_RULES$parent2.includes(child)) !== null && _NESTING_RULES$parent !== void 0 ? _NESTING_RULES$parent : false;
47
+ };
48
+ var shouldApplyMark = function shouldApplyMark(tag) {
49
+ return domParser.rules.some(function (rule) {
50
+ return 'mark' in rule && rule.tag === tag;
51
+ });
52
+ };
53
+ var isBlockElement = function isBlockElement(tag) {
54
+ return domParser.rules.some(function (rule) {
55
+ return rule.tag === tag && rule.node;
56
+ });
57
+ };
58
+ var getMarkTypes = function getMarkTypes(tags) {
59
+ var seen = new Set();
60
+ var marks = [];
61
+ var _iterator = _createForOfIteratorHelper(tags),
62
+ _step;
63
+ try {
64
+ var _loop = function _loop() {
65
+ var _domParser$rules$find;
66
+ var tag = _step.value;
67
+ var markType = (_domParser$rules$find = domParser.rules.find(function (rule) {
68
+ return rule.tag === tag;
69
+ })) === null || _domParser$rules$find === void 0 ? void 0 : _domParser$rules$find.mark;
70
+ if (markType && !seen.has(markType)) {
71
+ marks.push({
72
+ type: markType
73
+ });
74
+ seen.add(markType);
75
+ }
76
+ };
77
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
78
+ _loop();
79
+ }
80
+ } catch (err) {
81
+ _iterator.e(err);
82
+ } finally {
83
+ _iterator.f();
84
+ }
85
+ return marks;
86
+ };
87
+ var createParagraph = function createParagraph() {
88
+ var content = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
89
+ return {
90
+ type: 'paragraph',
91
+ content: content
92
+ };
93
+ };
94
+ var getBlockType = function getBlockType(tag) {
95
+ var rule = domParser.rules.find(function (r) {
96
+ return r.tag === tag;
97
+ });
98
+ return rule && 'node' in rule && rule.node ? rule.node : 'paragraph';
99
+ };
100
+ var createTextNode = function createTextNode(text, marks) {
101
+ var markTypes = getMarkTypes(marks);
102
+ return _objectSpread({
103
+ type: 'text',
104
+ text: text
105
+ }, markTypes.length > 0 && {
106
+ marks: markTypes
107
+ });
108
+ };
109
+ var addText = function addText(text, marks, content) {
110
+ if (text) {
111
+ content.push(createTextNode(text, marks));
112
+ }
113
+ };
114
+ var handleBlockElement = function handleBlockElement(tag, innerContent, marks, blocks, currentParagraphContent, parseNode, nestedContainer) {
115
+ // Push any accumulated content as paragraph before block element
116
+ if (currentParagraphContent.length > 0) {
117
+ blocks.push(createParagraph((0, _toConsumableArray2.default)(currentParagraphContent)));
118
+ currentParagraphContent.length = 0;
119
+ }
120
+ var blockType = getBlockType(tag);
121
+ var newMarks = shouldApplyMark(tag) ? [].concat((0, _toConsumableArray2.default)(marks), [tag]) : marks;
122
+ var parentNodeType = nestedContainer === null || nestedContainer === void 0 ? void 0 : nestedContainer.parentType;
123
+ if (nestedContainer && parentNodeType && isAllowedChild(parentNodeType, blockType)) {
124
+ var elementContent = [];
125
+ var childNestedContainer = canContainChildren(blockType) ? {
126
+ parentType: blockType,
127
+ children: elementContent
128
+ } : nestedContainer;
129
+ parseNode(innerContent, newMarks, childNestedContainer);
130
+ if (currentParagraphContent.length > 0) {
131
+ elementContent.push(createParagraph((0, _toConsumableArray2.default)(currentParagraphContent)));
132
+ currentParagraphContent.length = 0;
133
+ }
134
+ nestedContainer.children.push({
135
+ type: blockType,
136
+ content: elementContent.length > 0 ? elementContent : [createParagraph()]
137
+ });
138
+ } else if (canContainChildren(blockType)) {
139
+ var children = [];
140
+ parseNode(innerContent, newMarks, {
141
+ parentType: blockType,
142
+ children: children
143
+ });
144
+ blocks.push({
145
+ type: blockType,
146
+ content: children.length > 0 ? children : [createParagraph()]
147
+ });
148
+ } else {
149
+ // Regular block elements
150
+ parseNode(innerContent, newMarks, nestedContainer);
151
+
152
+ // Push content generated from block parsing
153
+ if (currentParagraphContent.length > 0) {
154
+ if (blockType === 'paragraph' || blockType === 'codeBlock') {
155
+ blocks.push({
156
+ type: blockType,
157
+ content: (0, _toConsumableArray2.default)(currentParagraphContent)
158
+ });
159
+ }
160
+ currentParagraphContent.length = 0;
161
+ }
162
+ }
163
+ };
164
+ var handleInlineElement = function handleInlineElement(tag, innerContent, marks, parseNode, nestedContainer) {
165
+ var newMarks = shouldApplyMark(tag) ? [].concat((0, _toConsumableArray2.default)(marks), [tag]) : marks;
166
+ parseNode(innerContent, newMarks, nestedContainer);
167
+ };
168
+
169
+ /**
170
+ * Simple SSR-compatible parser that recognises text wrapped in HTML elements
171
+ * and extracts their content as ADF.
172
+ *
173
+ * Designed specifically for parsing i18n strings for ADF which specifically need to be
174
+ * HTML strings for translation.
175
+ *
176
+ * Supports nested structures automatically derived from the ADF schema:
177
+ * - Lists: ul/ol → li (listItem)
178
+ * - Tables: table → tr (tableRow) → td/th (tableCell/tableHeader)
179
+ * - Paragraphs, code blocks, and text marks
180
+ * - Any other nested structures defined in the schema
181
+ *
182
+ * @param html - The HTML string to parse
183
+ * @returns ADF DocNode containing the parsed content
184
+ */
185
+ var parseHTMLTextContent = exports.parseHTMLTextContent = function parseHTMLTextContent(html) {
186
+ var blocks = [];
187
+ var currentParagraphContent = [];
188
+
189
+ // Simple regex-based parser that works in both SSR and browser
190
+ var _parseNode = function parseNode(content) {
191
+ var marks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
192
+ var nestedContainer = arguments.length > 2 ? arguments[2] : undefined;
193
+ // Match HTML tags and text content
194
+ // eslint-disable-next-line require-unicode-regexp
195
+ var tagRegex = /<\s*(\w+)([^>]*)>([\s\S]*?)<\s*\/\s*\1\s*>|([^<]+)/g;
196
+ var match = tagRegex.exec(content);
197
+ while (match !== null) {
198
+ if (match[4]) {
199
+ addText(match[4], marks, currentParagraphContent);
200
+ } else {
201
+ // HTML element
202
+ var tag = match[1].toLowerCase();
203
+ var innerContent = match[3];
204
+ if (isBlockElement(tag)) {
205
+ handleBlockElement(tag, innerContent, marks, blocks, currentParagraphContent, _parseNode, nestedContainer);
206
+ } else {
207
+ handleInlineElement(tag, innerContent, marks, _parseNode, nestedContainer);
208
+ }
209
+ }
210
+ match = tagRegex.exec(content);
211
+ }
212
+ };
213
+ _parseNode(html);
214
+
215
+ // Push any remaining content
216
+ if (currentParagraphContent.length > 0) {
217
+ blocks.push(createParagraph(currentParagraphContent));
218
+ }
219
+ return {
220
+ type: 'doc',
221
+ version: 1,
222
+ content: blocks.length > 0 ? blocks : [createParagraph()]
223
+ };
224
+ };
@@ -194,5 +194,15 @@ export default defineMessages({
194
194
  id: 'fabric.editor.imageEdit',
195
195
  defaultMessage: 'Edit image',
196
196
  description: 'Crop, flip or rotate the image'
197
+ },
198
+ error: {
199
+ id: 'fabric.editor.error.message.label',
200
+ defaultMessage: 'Error',
201
+ description: 'Label for error message icon'
202
+ },
203
+ success: {
204
+ id: 'fabric.editor.success.message.label',
205
+ defaultMessage: 'Success',
206
+ description: 'Label for success message icon'
197
207
  }
198
208
  });
@@ -4,7 +4,7 @@ import { isFedRamp } from './environment';
4
4
  import { normaliseSentryBreadcrumbs, SERIALIZABLE_ATTRIBUTES } from './normalise-sentry-breadcrumbs';
5
5
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
6
6
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
7
- const packageVersion = "110.49.1";
7
+ const packageVersion = "110.49.2";
8
8
  const sanitiseSentryEvents = (data, _hint) => {
9
9
  // Remove URL as it has UGC
10
10
  // Ignored via go/ees007
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
15
  import Layer from '../Layer';
16
16
  const packageName = "@atlaskit/editor-common";
17
- const packageVersion = "110.49.1";
17
+ const packageVersion = "110.49.2";
18
18
  const halfFocusRing = 1;
19
19
  const dropOffset = '0, 8';
20
20
  const fadeIn = keyframes({
@@ -5,8 +5,11 @@
5
5
 
6
6
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
7
7
  import { css, jsx } from '@emotion/react';
8
+ import { useIntl } from 'react-intl-next';
8
9
  import ErrorIcon from '@atlaskit/icon/core/status-error';
9
10
  import SuccessIcon from '@atlaskit/icon/core/status-success';
11
+ import { fg } from '@atlaskit/platform-feature-flags';
12
+ import commonMessages from '../../messages';
10
13
  const errorColor = css({
11
14
  color: "var(--ds-text-danger, #AE2E24)"
12
15
  });
@@ -40,26 +43,39 @@ export const HelperMessage = ({
40
43
  }, children);
41
44
  export const ErrorMessage = ({
42
45
  children
43
- }) => jsx("div", {
44
- css: () => {
45
- return [messageStyle(), errorColor];
46
- }
47
- }, jsx("span", {
48
- css: iconWrapperStyle
49
- }, jsx(ErrorIcon, {
50
- LEGACY_size: "small",
51
- label: "error",
52
- "aria-label": "error"
53
- })), children);
46
+ }) => {
47
+ const intl = useIntl();
48
+ return jsx("div", {
49
+ css: () => {
50
+ return [messageStyle(), errorColor];
51
+ }
52
+ }, jsx("span", {
53
+ css: iconWrapperStyle
54
+ }, fg('platform_editor_dec_a11y_fixes') ? jsx(ErrorIcon, {
55
+ LEGACY_size: "small",
56
+ label: intl.formatMessage(commonMessages.error)
57
+ })
58
+ /* eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx */ : jsx(ErrorIcon, {
59
+ LEGACY_size: "small",
60
+ label: "error",
61
+ "aria-label": "error"
62
+ })), children);
63
+ };
54
64
  export const ValidMessage = ({
55
65
  children
56
- }) => jsx("div", {
57
- css: () => {
58
- return [messageStyle(), validColor];
59
- }
60
- }, jsx("span", {
61
- css: iconWrapperStyle
62
- }, jsx(SuccessIcon, {
63
- LEGACY_size: "small",
64
- label: "success"
65
- })), children);
66
+ }) => {
67
+ const intl = useIntl();
68
+ return jsx("div", {
69
+ css: () => {
70
+ return [messageStyle(), validColor];
71
+ }
72
+ }, jsx("span", {
73
+ css: iconWrapperStyle
74
+ }, fg('platform_editor_dec_a11y_fixes') ? jsx(SuccessIcon, {
75
+ LEGACY_size: "small",
76
+ label: intl.formatMessage(commonMessages.success)
77
+ }) : jsx(SuccessIcon, {
78
+ LEGACY_size: "small",
79
+ label: "success"
80
+ })), children);
81
+ };
@@ -0,0 +1,16 @@
1
+ import { parseHTMLTextContent } from './parse-html-text-content';
2
+
3
+ /**
4
+ * Creates ADF from HTML string.
5
+ * This is particularly useful for providing translations in HTML to be supported and we convert back to ADF here
6
+ * See: https://developer.atlassian.com/platform/localization/i18n-formatting/avoiding-concatenation/
7
+ *
8
+ * This function only supports a subset of the schema as it is intended for translations, but it supports
9
+ * SSR as it has no DOM dependencies and is lightweight.
10
+ *
11
+ * @param html - The HTML string to convert to ADF
12
+ * @returns ADF DocNode or undefined if parsing fails
13
+ */
14
+ export const createADFFromHTML = html => {
15
+ return parseHTMLTextContent(html);
16
+ };
@@ -0,0 +1,179 @@
1
+ import { defaultSchema } from '@atlaskit/adf-schema/schema-default';
2
+ import { DOMParser } from '@atlaskit/editor-prosemirror/model';
3
+ const domParser = DOMParser.fromSchema(defaultSchema);
4
+ export const getNestingRulesFromSchema = () => {
5
+ const KEYWORDS = ['inline', 'block', 'text', 'leaf', 'group', 'unsupportedBlock', 'unsupportedInline'];
6
+ const rules = {};
7
+ for (const nodeType of Object.keys(defaultSchema.nodes)) {
8
+ var _defaultSchema$nodes$;
9
+ const contentStr = (_defaultSchema$nodes$ = defaultSchema.nodes[nodeType]) === null || _defaultSchema$nodes$ === void 0 ? void 0 : _defaultSchema$nodes$.spec.content;
10
+ if (!contentStr) {
11
+ continue;
12
+ }
13
+ const allowedChildren =
14
+ // eslint-disable-next-line require-unicode-regexp
15
+ (String(contentStr).match(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g) || []).filter((match, index, arr) => !KEYWORDS.includes(match) && defaultSchema.nodes[match] && arr.indexOf(match) === index);
16
+ if (allowedChildren.length > 0) {
17
+ rules[nodeType] = allowedChildren;
18
+ }
19
+ }
20
+ return rules;
21
+ };
22
+ const NESTING_RULES = getNestingRulesFromSchema();
23
+ const canContainChildren = nodeType => {
24
+ var _NESTING_RULES$nodeTy;
25
+ return !!((_NESTING_RULES$nodeTy = NESTING_RULES[nodeType]) !== null && _NESTING_RULES$nodeTy !== void 0 && _NESTING_RULES$nodeTy.length);
26
+ };
27
+ const isAllowedChild = (parent, child) => {
28
+ var _NESTING_RULES$parent, _NESTING_RULES$parent2;
29
+ return (_NESTING_RULES$parent = (_NESTING_RULES$parent2 = NESTING_RULES[parent]) === null || _NESTING_RULES$parent2 === void 0 ? void 0 : _NESTING_RULES$parent2.includes(child)) !== null && _NESTING_RULES$parent !== void 0 ? _NESTING_RULES$parent : false;
30
+ };
31
+ const shouldApplyMark = tag => domParser.rules.some(rule => 'mark' in rule && rule.tag === tag);
32
+ const isBlockElement = tag => domParser.rules.some(rule => rule.tag === tag && rule.node);
33
+ const getMarkTypes = tags => {
34
+ const seen = new Set();
35
+ const marks = [];
36
+ for (const tag of tags) {
37
+ var _domParser$rules$find;
38
+ const markType = (_domParser$rules$find = domParser.rules.find(rule => rule.tag === tag)) === null || _domParser$rules$find === void 0 ? void 0 : _domParser$rules$find.mark;
39
+ if (markType && !seen.has(markType)) {
40
+ marks.push({
41
+ type: markType
42
+ });
43
+ seen.add(markType);
44
+ }
45
+ }
46
+ return marks;
47
+ };
48
+ const createParagraph = (content = []) => ({
49
+ type: 'paragraph',
50
+ content
51
+ });
52
+ const getBlockType = tag => {
53
+ const rule = domParser.rules.find(r => r.tag === tag);
54
+ return rule && 'node' in rule && rule.node ? rule.node : 'paragraph';
55
+ };
56
+ const createTextNode = (text, marks) => {
57
+ const markTypes = getMarkTypes(marks);
58
+ return {
59
+ type: 'text',
60
+ text,
61
+ ...(markTypes.length > 0 && {
62
+ marks: markTypes
63
+ })
64
+ };
65
+ };
66
+ const addText = (text, marks, content) => {
67
+ if (text) {
68
+ content.push(createTextNode(text, marks));
69
+ }
70
+ };
71
+ const handleBlockElement = (tag, innerContent, marks, blocks, currentParagraphContent, parseNode, nestedContainer) => {
72
+ // Push any accumulated content as paragraph before block element
73
+ if (currentParagraphContent.length > 0) {
74
+ blocks.push(createParagraph([...currentParagraphContent]));
75
+ currentParagraphContent.length = 0;
76
+ }
77
+ const blockType = getBlockType(tag);
78
+ const newMarks = shouldApplyMark(tag) ? [...marks, tag] : marks;
79
+ const parentNodeType = nestedContainer === null || nestedContainer === void 0 ? void 0 : nestedContainer.parentType;
80
+ if (nestedContainer && parentNodeType && isAllowedChild(parentNodeType, blockType)) {
81
+ const elementContent = [];
82
+ const childNestedContainer = canContainChildren(blockType) ? {
83
+ parentType: blockType,
84
+ children: elementContent
85
+ } : nestedContainer;
86
+ parseNode(innerContent, newMarks, childNestedContainer);
87
+ if (currentParagraphContent.length > 0) {
88
+ elementContent.push(createParagraph([...currentParagraphContent]));
89
+ currentParagraphContent.length = 0;
90
+ }
91
+ nestedContainer.children.push({
92
+ type: blockType,
93
+ content: elementContent.length > 0 ? elementContent : [createParagraph()]
94
+ });
95
+ } else if (canContainChildren(blockType)) {
96
+ const children = [];
97
+ parseNode(innerContent, newMarks, {
98
+ parentType: blockType,
99
+ children
100
+ });
101
+ blocks.push({
102
+ type: blockType,
103
+ content: children.length > 0 ? children : [createParagraph()]
104
+ });
105
+ } else {
106
+ // Regular block elements
107
+ parseNode(innerContent, newMarks, nestedContainer);
108
+
109
+ // Push content generated from block parsing
110
+ if (currentParagraphContent.length > 0) {
111
+ if (blockType === 'paragraph' || blockType === 'codeBlock') {
112
+ blocks.push({
113
+ type: blockType,
114
+ content: [...currentParagraphContent]
115
+ });
116
+ }
117
+ currentParagraphContent.length = 0;
118
+ }
119
+ }
120
+ };
121
+ const handleInlineElement = (tag, innerContent, marks, parseNode, nestedContainer) => {
122
+ const newMarks = shouldApplyMark(tag) ? [...marks, tag] : marks;
123
+ parseNode(innerContent, newMarks, nestedContainer);
124
+ };
125
+
126
+ /**
127
+ * Simple SSR-compatible parser that recognises text wrapped in HTML elements
128
+ * and extracts their content as ADF.
129
+ *
130
+ * Designed specifically for parsing i18n strings for ADF which specifically need to be
131
+ * HTML strings for translation.
132
+ *
133
+ * Supports nested structures automatically derived from the ADF schema:
134
+ * - Lists: ul/ol → li (listItem)
135
+ * - Tables: table → tr (tableRow) → td/th (tableCell/tableHeader)
136
+ * - Paragraphs, code blocks, and text marks
137
+ * - Any other nested structures defined in the schema
138
+ *
139
+ * @param html - The HTML string to parse
140
+ * @returns ADF DocNode containing the parsed content
141
+ */
142
+ export const parseHTMLTextContent = html => {
143
+ const blocks = [];
144
+ const currentParagraphContent = [];
145
+
146
+ // Simple regex-based parser that works in both SSR and browser
147
+ const parseNode = (content, marks = [], nestedContainer) => {
148
+ // Match HTML tags and text content
149
+ // eslint-disable-next-line require-unicode-regexp
150
+ const tagRegex = /<\s*(\w+)([^>]*)>([\s\S]*?)<\s*\/\s*\1\s*>|([^<]+)/g;
151
+ let match = tagRegex.exec(content);
152
+ while (match !== null) {
153
+ if (match[4]) {
154
+ addText(match[4], marks, currentParagraphContent);
155
+ } else {
156
+ // HTML element
157
+ const tag = match[1].toLowerCase();
158
+ const innerContent = match[3];
159
+ if (isBlockElement(tag)) {
160
+ handleBlockElement(tag, innerContent, marks, blocks, currentParagraphContent, parseNode, nestedContainer);
161
+ } else {
162
+ handleInlineElement(tag, innerContent, marks, parseNode, nestedContainer);
163
+ }
164
+ }
165
+ match = tagRegex.exec(content);
166
+ }
167
+ };
168
+ parseNode(html);
169
+
170
+ // Push any remaining content
171
+ if (currentParagraphContent.length > 0) {
172
+ blocks.push(createParagraph(currentParagraphContent));
173
+ }
174
+ return {
175
+ type: 'doc',
176
+ version: 1,
177
+ content: blocks.length > 0 ? blocks : [createParagraph()]
178
+ };
179
+ };
@@ -194,5 +194,15 @@ export default defineMessages({
194
194
  id: 'fabric.editor.imageEdit',
195
195
  defaultMessage: 'Edit image',
196
196
  description: 'Crop, flip or rotate the image'
197
+ },
198
+ error: {
199
+ id: 'fabric.editor.error.message.label',
200
+ defaultMessage: 'Error',
201
+ description: 'Label for error message icon'
202
+ },
203
+ success: {
204
+ id: 'fabric.editor.success.message.label',
205
+ defaultMessage: 'Success',
206
+ description: 'Label for success message icon'
197
207
  }
198
208
  });
@@ -10,7 +10,7 @@ import { isFedRamp } from './environment';
10
10
  import { normaliseSentryBreadcrumbs, SERIALIZABLE_ATTRIBUTES } from './normalise-sentry-breadcrumbs';
11
11
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
12
12
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
13
- var packageVersion = "110.49.1";
13
+ var packageVersion = "110.49.2";
14
14
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
15
15
  // Remove URL as it has UGC
16
16
  // Ignored via go/ees007
@@ -21,7 +21,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
21
21
  import { fg } from '@atlaskit/platform-feature-flags';
22
22
  import Layer from '../Layer';
23
23
  var packageName = "@atlaskit/editor-common";
24
- var packageVersion = "110.49.1";
24
+ var packageVersion = "110.49.2";
25
25
  var halfFocusRing = 1;
26
26
  var dropOffset = '0, 8';
27
27
  var fadeIn = keyframes({
@@ -5,8 +5,11 @@
5
5
 
6
6
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
7
7
  import { css, jsx } from '@emotion/react';
8
+ import { useIntl } from 'react-intl-next';
8
9
  import ErrorIcon from '@atlaskit/icon/core/status-error';
9
10
  import SuccessIcon from '@atlaskit/icon/core/status-success';
11
+ import { fg } from '@atlaskit/platform-feature-flags';
12
+ import commonMessages from '../../messages';
10
13
  var errorColor = css({
11
14
  color: "var(--ds-text-danger, #AE2E24)"
12
15
  });
@@ -44,13 +47,18 @@ export var HelperMessage = function HelperMessage(_ref) {
44
47
  };
45
48
  export var ErrorMessage = function ErrorMessage(_ref2) {
46
49
  var children = _ref2.children;
50
+ var intl = useIntl();
47
51
  return jsx("div", {
48
52
  css: function css() {
49
53
  return [messageStyle(), errorColor];
50
54
  }
51
55
  }, jsx("span", {
52
56
  css: iconWrapperStyle
53
- }, jsx(ErrorIcon, {
57
+ }, fg('platform_editor_dec_a11y_fixes') ? jsx(ErrorIcon, {
58
+ LEGACY_size: "small",
59
+ label: intl.formatMessage(commonMessages.error)
60
+ })
61
+ /* eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx */ : jsx(ErrorIcon, {
54
62
  LEGACY_size: "small",
55
63
  label: "error",
56
64
  "aria-label": "error"
@@ -58,13 +66,17 @@ export var ErrorMessage = function ErrorMessage(_ref2) {
58
66
  };
59
67
  export var ValidMessage = function ValidMessage(_ref3) {
60
68
  var children = _ref3.children;
69
+ var intl = useIntl();
61
70
  return jsx("div", {
62
71
  css: function css() {
63
72
  return [messageStyle(), validColor];
64
73
  }
65
74
  }, jsx("span", {
66
75
  css: iconWrapperStyle
67
- }, jsx(SuccessIcon, {
76
+ }, fg('platform_editor_dec_a11y_fixes') ? jsx(SuccessIcon, {
77
+ LEGACY_size: "small",
78
+ label: intl.formatMessage(commonMessages.success)
79
+ }) : jsx(SuccessIcon, {
68
80
  LEGACY_size: "small",
69
81
  label: "success"
70
82
  })), children);
@@ -0,0 +1,16 @@
1
+ import { parseHTMLTextContent } from './parse-html-text-content';
2
+
3
+ /**
4
+ * Creates ADF from HTML string.
5
+ * This is particularly useful for providing translations in HTML to be supported and we convert back to ADF here
6
+ * See: https://developer.atlassian.com/platform/localization/i18n-formatting/avoiding-concatenation/
7
+ *
8
+ * This function only supports a subset of the schema as it is intended for translations, but it supports
9
+ * SSR as it has no DOM dependencies and is lightweight.
10
+ *
11
+ * @param html - The HTML string to convert to ADF
12
+ * @returns ADF DocNode or undefined if parsing fails
13
+ */
14
+ export var createADFFromHTML = function createADFFromHTML(html) {
15
+ return parseHTMLTextContent(html);
16
+ };
@@ -0,0 +1,217 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
6
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
7
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
8
+ import { defaultSchema } from '@atlaskit/adf-schema/schema-default';
9
+ import { DOMParser } from '@atlaskit/editor-prosemirror/model';
10
+ var domParser = DOMParser.fromSchema(defaultSchema);
11
+ export var getNestingRulesFromSchema = function getNestingRulesFromSchema() {
12
+ var KEYWORDS = ['inline', 'block', 'text', 'leaf', 'group', 'unsupportedBlock', 'unsupportedInline'];
13
+ var rules = {};
14
+ for (var _i = 0, _Object$keys = Object.keys(defaultSchema.nodes); _i < _Object$keys.length; _i++) {
15
+ var _defaultSchema$nodes$;
16
+ var nodeType = _Object$keys[_i];
17
+ var contentStr = (_defaultSchema$nodes$ = defaultSchema.nodes[nodeType]) === null || _defaultSchema$nodes$ === void 0 ? void 0 : _defaultSchema$nodes$.spec.content;
18
+ if (!contentStr) {
19
+ continue;
20
+ }
21
+ var allowedChildren =
22
+ // eslint-disable-next-line require-unicode-regexp
23
+ (String(contentStr).match(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g) || []).filter(function (match, index, arr) {
24
+ return !KEYWORDS.includes(match) && defaultSchema.nodes[match] && arr.indexOf(match) === index;
25
+ });
26
+ if (allowedChildren.length > 0) {
27
+ rules[nodeType] = allowedChildren;
28
+ }
29
+ }
30
+ return rules;
31
+ };
32
+ var NESTING_RULES = getNestingRulesFromSchema();
33
+ var canContainChildren = function canContainChildren(nodeType) {
34
+ var _NESTING_RULES$nodeTy;
35
+ return !!((_NESTING_RULES$nodeTy = NESTING_RULES[nodeType]) !== null && _NESTING_RULES$nodeTy !== void 0 && _NESTING_RULES$nodeTy.length);
36
+ };
37
+ var isAllowedChild = function isAllowedChild(parent, child) {
38
+ var _NESTING_RULES$parent, _NESTING_RULES$parent2;
39
+ return (_NESTING_RULES$parent = (_NESTING_RULES$parent2 = NESTING_RULES[parent]) === null || _NESTING_RULES$parent2 === void 0 ? void 0 : _NESTING_RULES$parent2.includes(child)) !== null && _NESTING_RULES$parent !== void 0 ? _NESTING_RULES$parent : false;
40
+ };
41
+ var shouldApplyMark = function shouldApplyMark(tag) {
42
+ return domParser.rules.some(function (rule) {
43
+ return 'mark' in rule && rule.tag === tag;
44
+ });
45
+ };
46
+ var isBlockElement = function isBlockElement(tag) {
47
+ return domParser.rules.some(function (rule) {
48
+ return rule.tag === tag && rule.node;
49
+ });
50
+ };
51
+ var getMarkTypes = function getMarkTypes(tags) {
52
+ var seen = new Set();
53
+ var marks = [];
54
+ var _iterator = _createForOfIteratorHelper(tags),
55
+ _step;
56
+ try {
57
+ var _loop = function _loop() {
58
+ var _domParser$rules$find;
59
+ var tag = _step.value;
60
+ var markType = (_domParser$rules$find = domParser.rules.find(function (rule) {
61
+ return rule.tag === tag;
62
+ })) === null || _domParser$rules$find === void 0 ? void 0 : _domParser$rules$find.mark;
63
+ if (markType && !seen.has(markType)) {
64
+ marks.push({
65
+ type: markType
66
+ });
67
+ seen.add(markType);
68
+ }
69
+ };
70
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
71
+ _loop();
72
+ }
73
+ } catch (err) {
74
+ _iterator.e(err);
75
+ } finally {
76
+ _iterator.f();
77
+ }
78
+ return marks;
79
+ };
80
+ var createParagraph = function createParagraph() {
81
+ var content = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
82
+ return {
83
+ type: 'paragraph',
84
+ content: content
85
+ };
86
+ };
87
+ var getBlockType = function getBlockType(tag) {
88
+ var rule = domParser.rules.find(function (r) {
89
+ return r.tag === tag;
90
+ });
91
+ return rule && 'node' in rule && rule.node ? rule.node : 'paragraph';
92
+ };
93
+ var createTextNode = function createTextNode(text, marks) {
94
+ var markTypes = getMarkTypes(marks);
95
+ return _objectSpread({
96
+ type: 'text',
97
+ text: text
98
+ }, markTypes.length > 0 && {
99
+ marks: markTypes
100
+ });
101
+ };
102
+ var addText = function addText(text, marks, content) {
103
+ if (text) {
104
+ content.push(createTextNode(text, marks));
105
+ }
106
+ };
107
+ var handleBlockElement = function handleBlockElement(tag, innerContent, marks, blocks, currentParagraphContent, parseNode, nestedContainer) {
108
+ // Push any accumulated content as paragraph before block element
109
+ if (currentParagraphContent.length > 0) {
110
+ blocks.push(createParagraph(_toConsumableArray(currentParagraphContent)));
111
+ currentParagraphContent.length = 0;
112
+ }
113
+ var blockType = getBlockType(tag);
114
+ var newMarks = shouldApplyMark(tag) ? [].concat(_toConsumableArray(marks), [tag]) : marks;
115
+ var parentNodeType = nestedContainer === null || nestedContainer === void 0 ? void 0 : nestedContainer.parentType;
116
+ if (nestedContainer && parentNodeType && isAllowedChild(parentNodeType, blockType)) {
117
+ var elementContent = [];
118
+ var childNestedContainer = canContainChildren(blockType) ? {
119
+ parentType: blockType,
120
+ children: elementContent
121
+ } : nestedContainer;
122
+ parseNode(innerContent, newMarks, childNestedContainer);
123
+ if (currentParagraphContent.length > 0) {
124
+ elementContent.push(createParagraph(_toConsumableArray(currentParagraphContent)));
125
+ currentParagraphContent.length = 0;
126
+ }
127
+ nestedContainer.children.push({
128
+ type: blockType,
129
+ content: elementContent.length > 0 ? elementContent : [createParagraph()]
130
+ });
131
+ } else if (canContainChildren(blockType)) {
132
+ var children = [];
133
+ parseNode(innerContent, newMarks, {
134
+ parentType: blockType,
135
+ children: children
136
+ });
137
+ blocks.push({
138
+ type: blockType,
139
+ content: children.length > 0 ? children : [createParagraph()]
140
+ });
141
+ } else {
142
+ // Regular block elements
143
+ parseNode(innerContent, newMarks, nestedContainer);
144
+
145
+ // Push content generated from block parsing
146
+ if (currentParagraphContent.length > 0) {
147
+ if (blockType === 'paragraph' || blockType === 'codeBlock') {
148
+ blocks.push({
149
+ type: blockType,
150
+ content: _toConsumableArray(currentParagraphContent)
151
+ });
152
+ }
153
+ currentParagraphContent.length = 0;
154
+ }
155
+ }
156
+ };
157
+ var handleInlineElement = function handleInlineElement(tag, innerContent, marks, parseNode, nestedContainer) {
158
+ var newMarks = shouldApplyMark(tag) ? [].concat(_toConsumableArray(marks), [tag]) : marks;
159
+ parseNode(innerContent, newMarks, nestedContainer);
160
+ };
161
+
162
+ /**
163
+ * Simple SSR-compatible parser that recognises text wrapped in HTML elements
164
+ * and extracts their content as ADF.
165
+ *
166
+ * Designed specifically for parsing i18n strings for ADF which specifically need to be
167
+ * HTML strings for translation.
168
+ *
169
+ * Supports nested structures automatically derived from the ADF schema:
170
+ * - Lists: ul/ol → li (listItem)
171
+ * - Tables: table → tr (tableRow) → td/th (tableCell/tableHeader)
172
+ * - Paragraphs, code blocks, and text marks
173
+ * - Any other nested structures defined in the schema
174
+ *
175
+ * @param html - The HTML string to parse
176
+ * @returns ADF DocNode containing the parsed content
177
+ */
178
+ export var parseHTMLTextContent = function parseHTMLTextContent(html) {
179
+ var blocks = [];
180
+ var currentParagraphContent = [];
181
+
182
+ // Simple regex-based parser that works in both SSR and browser
183
+ var _parseNode = function parseNode(content) {
184
+ var marks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
185
+ var nestedContainer = arguments.length > 2 ? arguments[2] : undefined;
186
+ // Match HTML tags and text content
187
+ // eslint-disable-next-line require-unicode-regexp
188
+ var tagRegex = /<\s*(\w+)([^>]*)>([\s\S]*?)<\s*\/\s*\1\s*>|([^<]+)/g;
189
+ var match = tagRegex.exec(content);
190
+ while (match !== null) {
191
+ if (match[4]) {
192
+ addText(match[4], marks, currentParagraphContent);
193
+ } else {
194
+ // HTML element
195
+ var tag = match[1].toLowerCase();
196
+ var innerContent = match[3];
197
+ if (isBlockElement(tag)) {
198
+ handleBlockElement(tag, innerContent, marks, blocks, currentParagraphContent, _parseNode, nestedContainer);
199
+ } else {
200
+ handleInlineElement(tag, innerContent, marks, _parseNode, nestedContainer);
201
+ }
202
+ }
203
+ match = tagRegex.exec(content);
204
+ }
205
+ };
206
+ _parseNode(html);
207
+
208
+ // Push any remaining content
209
+ if (currentParagraphContent.length > 0) {
210
+ blocks.push(createParagraph(currentParagraphContent));
211
+ }
212
+ return {
213
+ type: 'doc',
214
+ version: 1,
215
+ content: blocks.length > 0 ? blocks : [createParagraph()]
216
+ };
217
+ };
@@ -191,5 +191,15 @@ declare const _default: {
191
191
  defaultMessage: string;
192
192
  description: string;
193
193
  };
194
+ error: {
195
+ id: string;
196
+ defaultMessage: string;
197
+ description: string;
198
+ };
199
+ success: {
200
+ id: string;
201
+ defaultMessage: string;
202
+ description: string;
203
+ };
194
204
  };
195
205
  export default _default;
@@ -0,0 +1,13 @@
1
+ import type { DocNode } from '@atlaskit/adf-schema';
2
+ /**
3
+ * Creates ADF from HTML string.
4
+ * This is particularly useful for providing translations in HTML to be supported and we convert back to ADF here
5
+ * See: https://developer.atlassian.com/platform/localization/i18n-formatting/avoiding-concatenation/
6
+ *
7
+ * This function only supports a subset of the schema as it is intended for translations, but it supports
8
+ * SSR as it has no DOM dependencies and is lightweight.
9
+ *
10
+ * @param html - The HTML string to convert to ADF
11
+ * @returns ADF DocNode or undefined if parsing fails
12
+ */
13
+ export declare const createADFFromHTML: (html: string) => DocNode;
@@ -0,0 +1,19 @@
1
+ import type { DocNode } from '@atlaskit/adf-schema';
2
+ export declare const getNestingRulesFromSchema: () => Record<string, string[]>;
3
+ /**
4
+ * Simple SSR-compatible parser that recognises text wrapped in HTML elements
5
+ * and extracts their content as ADF.
6
+ *
7
+ * Designed specifically for parsing i18n strings for ADF which specifically need to be
8
+ * HTML strings for translation.
9
+ *
10
+ * Supports nested structures automatically derived from the ADF schema:
11
+ * - Lists: ul/ol → li (listItem)
12
+ * - Tables: table → tr (tableRow) → td/th (tableCell/tableHeader)
13
+ * - Paragraphs, code blocks, and text marks
14
+ * - Any other nested structures defined in the schema
15
+ *
16
+ * @param html - The HTML string to parse
17
+ * @returns ADF DocNode containing the parsed content
18
+ */
19
+ export declare const parseHTMLTextContent: (html: string) => DocNode;
@@ -191,5 +191,15 @@ declare const _default: {
191
191
  defaultMessage: string;
192
192
  description: string;
193
193
  };
194
+ error: {
195
+ id: string;
196
+ defaultMessage: string;
197
+ description: string;
198
+ };
199
+ success: {
200
+ id: string;
201
+ defaultMessage: string;
202
+ description: string;
203
+ };
194
204
  };
195
205
  export default _default;
@@ -0,0 +1,13 @@
1
+ import type { DocNode } from '@atlaskit/adf-schema';
2
+ /**
3
+ * Creates ADF from HTML string.
4
+ * This is particularly useful for providing translations in HTML to be supported and we convert back to ADF here
5
+ * See: https://developer.atlassian.com/platform/localization/i18n-formatting/avoiding-concatenation/
6
+ *
7
+ * This function only supports a subset of the schema as it is intended for translations, but it supports
8
+ * SSR as it has no DOM dependencies and is lightweight.
9
+ *
10
+ * @param html - The HTML string to convert to ADF
11
+ * @returns ADF DocNode or undefined if parsing fails
12
+ */
13
+ export declare const createADFFromHTML: (html: string) => DocNode;
@@ -0,0 +1,19 @@
1
+ import type { DocNode } from '@atlaskit/adf-schema';
2
+ export declare const getNestingRulesFromSchema: () => Record<string, string[]>;
3
+ /**
4
+ * Simple SSR-compatible parser that recognises text wrapped in HTML elements
5
+ * and extracts their content as ADF.
6
+ *
7
+ * Designed specifically for parsing i18n strings for ADF which specifically need to be
8
+ * HTML strings for translation.
9
+ *
10
+ * Supports nested structures automatically derived from the ADF schema:
11
+ * - Lists: ul/ol → li (listItem)
12
+ * - Tables: table → tr (tableRow) → td/th (tableCell/tableHeader)
13
+ * - Paragraphs, code blocks, and text marks
14
+ * - Any other nested structures defined in the schema
15
+ *
16
+ * @param html - The HTML string to parse
17
+ * @returns ADF DocNode containing the parsed content
18
+ */
19
+ export declare const parseHTMLTextContent: (html: string) => DocNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-common",
3
- "version": "110.49.2",
3
+ "version": "110.50.0",
4
4
  "description": "A package that contains common classes and components for editor and renderer",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -81,7 +81,7 @@
81
81
  "@atlaskit/task-decision": "^19.2.0",
82
82
  "@atlaskit/textfield": "^8.2.0",
83
83
  "@atlaskit/theme": "^21.0.0",
84
- "@atlaskit/tmp-editor-statsig": "^16.2.0",
84
+ "@atlaskit/tmp-editor-statsig": "^16.3.0",
85
85
  "@atlaskit/tokens": "^9.0.0",
86
86
  "@atlaskit/tooltip": "^20.11.0",
87
87
  "@atlaskit/width-detector": "^5.0.0",
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@atlaskit/editor-common/utils/create-adf-from-html",
3
+ "main": "../../dist/cjs/utils/create-adf-from-html.js",
4
+ "module": "../../dist/esm/utils/create-adf-from-html.js",
5
+ "module:es2019": "../../dist/es2019/utils/create-adf-from-html.js",
6
+ "sideEffects": [
7
+ "**/*.compiled.css"
8
+ ],
9
+ "types": "../../dist/types/utils/create-adf-from-html.d.ts",
10
+ "typesVersions": {
11
+ ">=4.5 <5.9": {
12
+ "*": [
13
+ "../../dist/types-ts4.5/utils/create-adf-from-html.d.ts"
14
+ ]
15
+ }
16
+ }
17
+ }