@atlaskit/editor-plugin-code-block 12.1.6 → 12.1.7

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/editor-commands/index.js +5 -3
  3. package/dist/cjs/pm-plugins/toolbar.js +23 -24
  4. package/dist/cjs/ui/CodeBlockLanguagePicker.js +45 -0
  5. package/dist/cjs/ui/LanguagePicker.js +63 -10
  6. package/dist/cjs/ui/language-picker-options.js +21 -4
  7. package/dist/cjs/ui/recent-languages.js +50 -0
  8. package/dist/es2019/editor-commands/index.js +5 -2
  9. package/dist/es2019/pm-plugins/toolbar.js +168 -167
  10. package/dist/es2019/ui/CodeBlockLanguagePicker.js +31 -0
  11. package/dist/es2019/ui/LanguagePicker.js +41 -9
  12. package/dist/es2019/ui/language-picker-options.js +15 -4
  13. package/dist/es2019/ui/recent-languages.js +38 -0
  14. package/dist/esm/editor-commands/index.js +5 -3
  15. package/dist/esm/pm-plugins/toolbar.js +24 -25
  16. package/dist/esm/ui/CodeBlockLanguagePicker.js +36 -0
  17. package/dist/esm/ui/LanguagePicker.js +64 -11
  18. package/dist/esm/ui/language-picker-options.js +21 -4
  19. package/dist/esm/ui/recent-languages.js +43 -0
  20. package/dist/types/editor-commands/index.d.ts +2 -1
  21. package/dist/types/ui/CodeBlockLanguagePicker.d.ts +5 -0
  22. package/dist/types/ui/LanguagePicker.d.ts +7 -5
  23. package/dist/types/ui/language-picker-options.d.ts +2 -0
  24. package/dist/types/ui/recent-languages.d.ts +4 -0
  25. package/dist/types-ts4.5/editor-commands/index.d.ts +2 -1
  26. package/dist/types-ts4.5/ui/CodeBlockLanguagePicker.d.ts +5 -0
  27. package/dist/types-ts4.5/ui/LanguagePicker.d.ts +7 -5
  28. package/dist/types-ts4.5/ui/language-picker-options.d.ts +2 -0
  29. package/dist/types-ts4.5/ui/recent-languages.d.ts +4 -0
  30. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-plugin-code-block
2
2
 
3
+ ## 12.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a0dc04472d27b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a0dc04472d27b) -
8
+ Add recently used code block languages and analytics metadata
9
+ - Updated dependencies
10
+
3
11
  ## 12.1.6
4
12
 
5
13
  ### Patch Changes
@@ -51,7 +51,7 @@ var removeCodeBlock = exports.removeCodeBlock = function removeCodeBlock(state,
51
51
  return true;
52
52
  };
53
53
  var changeLanguage = exports.changeLanguage = function changeLanguage(editorAnalyticsAPI) {
54
- return function (language) {
54
+ return function (language, selectionSource) {
55
55
  return function (state, dispatch) {
56
56
  var _pluginKey$getState;
57
57
  var codeBlock = state.schema.nodes.codeBlock;
@@ -69,9 +69,11 @@ var changeLanguage = exports.changeLanguage = function changeLanguage(editorAnal
69
69
  editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({
70
70
  action: _analytics.ACTION.LANGUAGE_SELECTED,
71
71
  actionSubject: _analytics.ACTION_SUBJECT.CODE_BLOCK,
72
- attributes: {
72
+ attributes: _objectSpread({
73
73
  language: language !== null && language !== void 0 ? language : 'none'
74
- },
74
+ }, selectionSource ? {
75
+ selectionSource: selectionSource
76
+ } : {}),
75
77
  eventType: _analytics.EVENT_TYPE.TRACK
76
78
  })(result);
77
79
  dispatch(result);
@@ -20,9 +20,9 @@ var _textWrap = _interopRequireDefault(require("@atlaskit/icon/core/text-wrap"))
20
20
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
21
21
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
22
22
  var _editorCommands = require("../editor-commands");
23
+ var _CodeBlockLanguagePicker = require("../ui/CodeBlockLanguagePicker");
23
24
  var _WrapIcon = require("../ui/icons/WrapIcon");
24
25
  var _languagePickerOptions = require("../ui/language-picker-options");
25
- var _LanguagePicker = require("../ui/LanguagePicker");
26
26
  var _codeBlockCopySelectionPlugin = require("./codeBlockCopySelectionPlugin");
27
27
  var _languageList = require("./language-list");
28
28
  var _pluginKey = require("./plugin-key");
@@ -33,6 +33,18 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig() {
33
33
  var allowCopyToClipboard = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
34
34
  var api = arguments.length > 1 ? arguments[1] : undefined;
35
35
  var overrideLanguageName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
36
+ var languageList = (0, _languageList.createLanguageList)(overrideLanguageName ? _languageList.DEFAULT_LANGUAGES.map(function (languageOption) {
37
+ return _objectSpread(_objectSpread({}, languageOption), {}, {
38
+ name: overrideLanguageName(languageOption.name)
39
+ });
40
+ }) : _languageList.DEFAULT_LANGUAGES);
41
+ var languagePickerOptions = languageList.map(function (lang) {
42
+ return {
43
+ label: lang.name,
44
+ value: (0, _languageList.getLanguageIdentifier)(lang),
45
+ alias: lang.alias
46
+ };
47
+ });
36
48
  return function (state, _ref) {
37
49
  var _api$editorViewMode, _api$decorations$acti, _api$decorations, _api$analytics, _codeBlockState$pos, _node$attrs;
38
50
  var formatMessage = _ref.formatMessage;
@@ -53,23 +65,15 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig() {
53
65
  var isWrapped = (0, _codeBlock.isCodeBlockWordWrapEnabled)(node);
54
66
  var areLineNumbersVisible = (0, _codeBlock.areCodeBlockLineNumbersVisible)(node);
55
67
  var language = node === null || node === void 0 || (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.language;
56
- var languageList = (0, _languageList.createLanguageList)(overrideLanguageName ? _languageList.DEFAULT_LANGUAGES.map(function (language) {
57
- return _objectSpread(_objectSpread({}, language), {}, {
58
- name: overrideLanguageName(language.name)
59
- });
60
- }) : _languageList.DEFAULT_LANGUAGES);
61
- var options = languageList.map(function (lang) {
62
- return {
63
- label: lang.name,
64
- value: (0, _languageList.getLanguageIdentifier)(lang),
65
- alias: lang.alias
66
- };
68
+ // Keep fresh option objects for the legacy toolbar select so reopening it
69
+ // continues to start from the top rather than preserving the previously
70
+ // focused option by reference.
71
+ var languageSelectOptions = languagePickerOptions.map(function (option) {
72
+ return _objectSpread({}, option);
67
73
  });
68
-
69
- // If language is not undefined search for it in the value and then search in the aliases
70
- var defaultValue = language ? options.find(function (option) {
74
+ var defaultValue = language ? languageSelectOptions.find(function (option) {
71
75
  return option.value === language;
72
- }) || options.find(function (option) {
76
+ }) || languageSelectOptions.find(function (option) {
73
77
  return option.alias.includes(language);
74
78
  }) : null;
75
79
  var languageSelect = {
@@ -81,16 +85,11 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig() {
81
85
  },
82
86
  defaultValue: defaultValue,
83
87
  placeholder: formatMessage(_messages.codeBlockButtonMessages.selectLanguage),
84
- options: options,
88
+ options: languageSelectOptions,
85
89
  filterOption: languageListFilter
86
90
  };
87
91
  var languagePicker;
88
92
  if ((0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) && (0, _platformFeatureFlags.fg)('platform_editor_code_block_add_line_number_button')) {
89
- var languagePickerOptions = options;
90
- var groupedOptions = (0, _languagePickerOptions.createGroupedLanguageOptions)({
91
- formatMessage: formatMessage,
92
- languages: languagePickerOptions
93
- });
94
93
  var defaultPickerValue = language ? languagePickerOptions.find(function (option) {
95
94
  return language === _languagePickerOptions.NONE_LANGUAGE_VALUE ? option.value === _languagePickerOptions.PLAIN_TEXT_LANGUAGE_VALUE : option.value === language || option.alias.includes(language);
96
95
  }) : undefined;
@@ -101,13 +100,13 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig() {
101
100
  if (!view) {
102
101
  return null;
103
102
  }
104
- return /*#__PURE__*/_react.default.createElement(_LanguagePicker.LanguagePicker, {
103
+ return /*#__PURE__*/_react.default.createElement(_CodeBlockLanguagePicker.CodeBlockLanguagePicker, {
105
104
  api: api,
106
105
  defaultValue: defaultPickerValue,
107
106
  editorView: view,
108
107
  filterOption: languageListFilter,
109
108
  formatMessage: formatMessage,
110
- options: groupedOptions
109
+ languagePickerOptions: languagePickerOptions
111
110
  });
112
111
  }
113
112
  };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.CodeBlockLanguagePicker = void 0;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ var _LanguagePicker = require("./LanguagePicker");
12
+ var _recentLanguages = require("./recent-languages");
13
+ 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); }
14
+ var CodeBlockLanguagePicker = exports.CodeBlockLanguagePicker = function CodeBlockLanguagePicker(_ref) {
15
+ var api = _ref.api,
16
+ defaultValue = _ref.defaultValue,
17
+ editorView = _ref.editorView,
18
+ filterOption = _ref.filterOption,
19
+ formatMessage = _ref.formatMessage,
20
+ languagePickerOptions = _ref.languagePickerOptions;
21
+ var _useState = (0, _react.useState)(function () {
22
+ return (0, _recentLanguages.getRecentLanguages)();
23
+ }),
24
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
25
+ recentLanguageValues = _useState2[0],
26
+ setRecentLanguageValues = _useState2[1];
27
+ var refreshRecentLanguages = (0, _react.useCallback)(function () {
28
+ setRecentLanguageValues((0, _recentLanguages.getRecentLanguages)());
29
+ }, []);
30
+ var handleLanguageSelect = (0, _react.useCallback)(function (language) {
31
+ (0, _recentLanguages.saveRecentLanguage)(language);
32
+ setRecentLanguageValues((0, _recentLanguages.getRecentLanguages)());
33
+ }, []);
34
+ return /*#__PURE__*/_react.default.createElement(_LanguagePicker.LanguagePicker, {
35
+ api: api,
36
+ defaultValue: defaultValue,
37
+ editorView: editorView,
38
+ filterOption: filterOption,
39
+ formatMessage: formatMessage,
40
+ languagePickerOptions: languagePickerOptions,
41
+ recentLanguageValues: recentLanguageValues,
42
+ onLanguageSelect: handleLanguageSelect,
43
+ onMenuOpen: refreshRecentLanguages
44
+ });
45
+ };
@@ -18,7 +18,11 @@ var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-d
18
18
  var _compiled = require("@atlaskit/primitives/compiled");
19
19
  var _select = require("@atlaskit/select");
20
20
  var _editorCommands = require("../editor-commands");
21
+ var _languagePickerOptions = require("./language-picker-options");
21
22
  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); }
23
+ 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; } } }; }
24
+ 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; } }
25
+ 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; }
22
26
  var pickerOptionStyles = null;
23
27
  var styles = {
24
28
  divider: "_h7alglyw _179rglyw _mqm2ia51 _1bsb1osq",
@@ -57,6 +61,25 @@ var menuPopperProps = {
57
61
  enabled: false
58
62
  }]
59
63
  };
64
+ var getRecentlyUsedLanguages = function getRecentlyUsedLanguages(recentLanguageValues, optionsByValue) {
65
+ var recentlyUsedLanguages = [];
66
+ var _iterator = _createForOfIteratorHelper(recentLanguageValues),
67
+ _step;
68
+ try {
69
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
70
+ var recentLanguageValue = _step.value;
71
+ var option = optionsByValue.get(recentLanguageValue);
72
+ if (option) {
73
+ recentlyUsedLanguages.push(option);
74
+ }
75
+ }
76
+ } catch (err) {
77
+ _iterator.e(err);
78
+ } finally {
79
+ _iterator.f();
80
+ }
81
+ return recentlyUsedLanguages;
82
+ };
60
83
  var LanguagePicker = exports.LanguagePicker = function LanguagePicker(_ref) {
61
84
  var _api$analytics, _defaultValue$label;
62
85
  var api = _ref.api,
@@ -64,28 +87,58 @@ var LanguagePicker = exports.LanguagePicker = function LanguagePicker(_ref) {
64
87
  editorView = _ref.editorView,
65
88
  filterOption = _ref.filterOption,
66
89
  formatMessage = _ref.formatMessage,
67
- options = _ref.options;
90
+ languagePickerOptions = _ref.languagePickerOptions,
91
+ _ref$recentLanguageVa = _ref.recentLanguageValues,
92
+ recentLanguageValues = _ref$recentLanguageVa === void 0 ? [] : _ref$recentLanguageVa,
93
+ onLanguageSelect = _ref.onLanguageSelect,
94
+ onMenuOpen = _ref.onMenuOpen;
68
95
  var editorAnalyticsAPI = api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
69
96
  var label = (_defaultValue$label = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.label) !== null && _defaultValue$label !== void 0 ? _defaultValue$label : formatMessage(_messages.codeBlockButtonMessages.selectLanguage);
70
97
  var selectLanguageLabel = formatMessage(_messages.codeBlockButtonMessages.selectLanguage);
71
- var _useState = (0, _react.useState)(''),
98
+ var _useState = (0, _react.useState)(false),
72
99
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
73
- inputValue = _useState2[0],
74
- setInputValue = _useState2[1];
100
+ hasSearchQuery = _useState2[0],
101
+ setHasSearchQuery = _useState2[1];
102
+ var inputValueRef = (0, _react.useRef)('');
103
+ var optionsByValue = (0, _react.useMemo)(function () {
104
+ return new Map(languagePickerOptions.map(function (option) {
105
+ return [option.value, option];
106
+ }));
107
+ }, [languagePickerOptions]);
108
+ var recentlyUsedLanguages = (0, _react.useMemo)(function () {
109
+ return getRecentlyUsedLanguages(recentLanguageValues, optionsByValue);
110
+ }, [recentLanguageValues, optionsByValue]);
111
+ var options = (0, _react.useMemo)(function () {
112
+ return (0, _languagePickerOptions.createGroupedLanguageOptions)({
113
+ formatMessage: formatMessage,
114
+ languages: languagePickerOptions,
115
+ recentlyUsedLanguages: recentlyUsedLanguages
116
+ });
117
+ }, [formatMessage, languagePickerOptions, recentlyUsedLanguages]);
75
118
  var searchOptions = (0, _react.useMemo)(function () {
76
119
  return options.flatMap(function (group) {
77
120
  return group.options;
78
121
  });
79
122
  }, [options]);
80
- var hasSearchQuery = inputValue.trim().length > 0;
81
123
  var handleChange = (0, _react.useCallback)(function (option) {
124
+ var _option$selectionSour;
82
125
  if (!option) {
83
126
  return;
84
127
  }
85
- (0, _editorCommands.changeLanguage)(editorAnalyticsAPI)(option.value)(editorView.state, editorView.dispatch);
86
- }, [editorAnalyticsAPI, editorView]);
87
- var handleInputChange = (0, _react.useCallback)(function (newInputValue) {
88
- setInputValue(newInputValue);
128
+ var isSearchSelection = inputValueRef.current.trim().length > 0;
129
+ var selectionSource = isSearchSelection ? 'search' : (_option$selectionSour = option.selectionSource) !== null && _option$selectionSour !== void 0 ? _option$selectionSour : 'all';
130
+ var commandSucceeded = (0, _editorCommands.changeLanguage)(editorAnalyticsAPI)(option.value, selectionSource)(editorView.state, editorView.dispatch);
131
+ if (commandSucceeded) {
132
+ onLanguageSelect === null || onLanguageSelect === void 0 || onLanguageSelect(option.value);
133
+ }
134
+ }, [editorAnalyticsAPI, editorView, onLanguageSelect]);
135
+ var handleInputChange = (0, _react.useCallback)(function (newInputValue, actionMeta) {
136
+ // React-select clears the input as part of selecting a value before onChange fires.
137
+ // Keep the last user-typed query so handleChange can report search selections correctly.
138
+ if (!actionMeta || actionMeta.action === 'input-change') {
139
+ inputValueRef.current = newInputValue;
140
+ }
141
+ setHasSearchQuery(newInputValue.trim().length > 0);
89
142
  return newInputValue;
90
143
  }, []);
91
144
  var renderTarget = (0, _react.useCallback)(function (_ref2) {
@@ -110,13 +163,13 @@ var LanguagePicker = exports.LanguagePicker = function LanguagePicker(_ref) {
110
163
  return /*#__PURE__*/_react.default.createElement(_select.PopupSelect, {
111
164
  components: popupSelectComponents,
112
165
  filterOption: filterOption,
113
- inputValue: inputValue,
114
166
  label: selectLanguageLabel,
115
167
  maxMenuHeight: 300,
116
168
  minMenuWidth: 200,
117
169
  menuPlacement: "auto",
118
170
  onChange: handleChange,
119
171
  onInputChange: handleInputChange,
172
+ onMenuOpen: onMenuOpen,
120
173
  options: hasSearchQuery ? searchOptions : options,
121
174
  popperProps: menuPopperProps,
122
175
  searchThreshold: -1,
@@ -6,7 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.getDetectLanguageOption = exports.createGroupedLanguageOptions = exports.PLAIN_TEXT_LANGUAGE_VALUE = exports.NONE_LANGUAGE_VALUE = exports.DETECT_LANGUAGE_VALUE = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
10
  var _messages = require("@atlaskit/editor-common/messages");
11
+ 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; }
12
+ 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; }
10
13
  var NONE_LANGUAGE_VALUE = exports.NONE_LANGUAGE_VALUE = 'none';
11
14
  var DETECT_LANGUAGE_VALUE = exports.DETECT_LANGUAGE_VALUE = 'autodetect';
12
15
  var PLAIN_TEXT_LANGUAGE_VALUE = exports.PLAIN_TEXT_LANGUAGE_VALUE = 'text';
@@ -14,6 +17,7 @@ var getDetectLanguageOption = exports.getDetectLanguageOption = function getDete
14
17
  return {
15
18
  alias: [DETECT_LANGUAGE_VALUE],
16
19
  label: formatMessage(_messages.codeBlockButtonMessages.detectLanguage),
20
+ selectionSource: 'pinned',
17
21
  value: DETECT_LANGUAGE_VALUE
18
22
  };
19
23
  };
@@ -22,24 +26,37 @@ var createGroupedLanguageOptions = exports.createGroupedLanguageOptions = functi
22
26
  languages = _ref.languages,
23
27
  _ref$recentlyUsedLang = _ref.recentlyUsedLanguages,
24
28
  recentlyUsedLanguages = _ref$recentlyUsedLang === void 0 ? [] : _ref$recentlyUsedLang;
29
+ var recentlyUsedLanguageValues = new Set(recentlyUsedLanguages.map(function (language) {
30
+ return language.value;
31
+ }));
25
32
  var allLanguages = languages.filter(function (language) {
26
- return language.value !== NONE_LANGUAGE_VALUE && language.value !== PLAIN_TEXT_LANGUAGE_VALUE;
33
+ return language.value !== NONE_LANGUAGE_VALUE && language.value !== PLAIN_TEXT_LANGUAGE_VALUE && !recentlyUsedLanguageValues.has(language.value);
27
34
  });
28
35
  var plainTextOption = languages.find(function (language) {
29
36
  return language.value === PLAIN_TEXT_LANGUAGE_VALUE;
30
37
  });
31
38
  var pinnedOptions = [getDetectLanguageOption(formatMessage)];
32
39
  if (plainTextOption) {
33
- pinnedOptions.push(plainTextOption);
40
+ pinnedOptions.push(_objectSpread(_objectSpread({}, plainTextOption), {}, {
41
+ selectionSource: 'pinned'
42
+ }));
34
43
  }
35
44
  return [{
36
45
  label: '',
37
46
  options: pinnedOptions
38
47
  }].concat((0, _toConsumableArray2.default)(recentlyUsedLanguages.length > 0 ? [{
39
48
  label: formatMessage(_messages.codeBlockButtonMessages.recentlyUsed),
40
- options: recentlyUsedLanguages
49
+ options: recentlyUsedLanguages.map(function (language) {
50
+ return _objectSpread(_objectSpread({}, language), {}, {
51
+ selectionSource: 'recentlyUsed'
52
+ });
53
+ })
41
54
  }] : []), [{
42
55
  label: formatMessage(_messages.codeBlockButtonMessages.all),
43
- options: allLanguages
56
+ options: allLanguages.map(function (language) {
57
+ return _objectSpread(_objectSpread({}, language), {}, {
58
+ selectionSource: 'all'
59
+ });
60
+ })
44
61
  }]);
45
62
  };
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.saveRecentLanguage = exports.getRecentLanguages = exports.clearRecentLanguages = exports.RECENT_LANGUAGES_STORAGE_KEY = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _storageClient = require("@atlaskit/frontend-utilities/storage-client");
10
+ var _languageList = require("../pm-plugins/language-list");
11
+ var _languagePickerOptions = require("./language-picker-options");
12
+ var RECENT_LANGUAGES_STORAGE_KEY = exports.RECENT_LANGUAGES_STORAGE_KEY = 'recently-used-languages';
13
+ var RECENT_LANGUAGES_STORAGE_CLIENT_KEY = '@atlaskit/editor-plugin-code-block';
14
+ var MAX_RECENT_LANGUAGES = 3;
15
+ var RECENT_LANGUAGE_BLOCKLIST = new Set([_languagePickerOptions.DETECT_LANGUAGE_VALUE, _languagePickerOptions.NONE_LANGUAGE_VALUE, _languagePickerOptions.PLAIN_TEXT_LANGUAGE_VALUE]);
16
+ var KNOWN_LANGUAGE_VALUES = new Set(_languageList.DEFAULT_LANGUAGES.map(function (language) {
17
+ return (0, _languageList.getLanguageIdentifier)(language);
18
+ }));
19
+ var recentLanguagesStorageClient = new _storageClient.StorageClient(RECENT_LANGUAGES_STORAGE_CLIENT_KEY);
20
+ var isValidRecentLanguage = function isValidRecentLanguage(language) {
21
+ return KNOWN_LANGUAGE_VALUES.has(language) && !RECENT_LANGUAGE_BLOCKLIST.has(language);
22
+ };
23
+ var readRecentLanguages = function readRecentLanguages() {
24
+ var storedValue = recentLanguagesStorageClient.getItem(RECENT_LANGUAGES_STORAGE_KEY);
25
+ return Array.isArray(storedValue) ? storedValue : [];
26
+ };
27
+ var getRecentLanguages = exports.getRecentLanguages = function getRecentLanguages() {
28
+ try {
29
+ return readRecentLanguages();
30
+ } catch (_unused) {
31
+ return [];
32
+ }
33
+ };
34
+ var saveRecentLanguage = exports.saveRecentLanguage = function saveRecentLanguage(language) {
35
+ if (!isValidRecentLanguage(language)) {
36
+ return;
37
+ }
38
+ try {
39
+ var recentLanguages = readRecentLanguages();
40
+ var nextRecentLanguages = Array.from(new Set([language].concat((0, _toConsumableArray2.default)(recentLanguages)))).slice(0, MAX_RECENT_LANGUAGES);
41
+
42
+ // StorageClient only exposes setItemWithExpiry; omitting the duration stores without expiry.
43
+ recentLanguagesStorageClient.setItemWithExpiry(RECENT_LANGUAGES_STORAGE_KEY, nextRecentLanguages);
44
+ } catch (_unused2) {
45
+ return;
46
+ }
47
+ };
48
+ var clearRecentLanguages = exports.clearRecentLanguages = function clearRecentLanguages() {
49
+ recentLanguagesStorageClient.removeItem(RECENT_LANGUAGES_STORAGE_KEY);
50
+ };
@@ -40,7 +40,7 @@ export const removeCodeBlock = (state, dispatch) => {
40
40
  }
41
41
  return true;
42
42
  };
43
- export const changeLanguage = editorAnalyticsAPI => language => (state, dispatch) => {
43
+ export const changeLanguage = editorAnalyticsAPI => (language, selectionSource) => (state, dispatch) => {
44
44
  var _pluginKey$getState;
45
45
  const {
46
46
  codeBlock
@@ -61,7 +61,10 @@ export const changeLanguage = editorAnalyticsAPI => language => (state, dispatch
61
61
  action: ACTION.LANGUAGE_SELECTED,
62
62
  actionSubject: ACTION_SUBJECT.CODE_BLOCK,
63
63
  attributes: {
64
- language: language !== null && language !== void 0 ? language : 'none'
64
+ language: language !== null && language !== void 0 ? language : 'none',
65
+ ...(selectionSource ? {
66
+ selectionSource
67
+ } : {})
65
68
  },
66
69
  eventType: EVENT_TYPE.TRACK
67
70
  })(result);