@instructure/canvas-rce 6.0.0 → 7.2.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.
Files changed (120) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/__tests__/common/indicate.test.js +5 -6
  3. package/es/bridge/Bridge.js +2 -4
  4. package/es/canvasFileBrowser/FileBrowser.js +2 -4
  5. package/es/common/browser.js +2 -2
  6. package/es/common/fileUrl.js +13 -3
  7. package/es/defaultTinymceConfig.d.ts +1 -1
  8. package/es/defaultTinymceConfig.js +149 -114
  9. package/es/enhance-user-content/enhance_user_content.js +7 -1
  10. package/es/enhance-user-content/instructure_helper.js +4 -0
  11. package/es/enhance-user-content/youtube_overlay.d.ts +1 -0
  12. package/es/enhance-user-content/youtube_overlay.js +87 -0
  13. package/es/format-message.d.js +1 -0
  14. package/es/format-message.js +5 -0
  15. package/es/index.d.ts +1 -1
  16. package/es/rce/RCE.d.ts +0 -1
  17. package/es/rce/RCE.js +5 -10
  18. package/es/rce/RCEGlobals.d.ts +0 -2
  19. package/es/rce/RCEGlobals.js +0 -1
  20. package/es/rce/RCEVariants.d.ts +8 -3
  21. package/es/rce/RCEVariants.js +36 -10
  22. package/es/rce/RCEWrapper.d.ts +3 -5
  23. package/es/rce/RCEWrapper.js +68 -83
  24. package/es/rce/RCEWrapperProps.d.ts +1 -1
  25. package/es/rce/ShowOnFocusButton/index.js +4 -2
  26. package/es/rce/StatusBar.js +61 -15
  27. package/es/rce/alertHandler.js +6 -7
  28. package/es/rce/plugins/instructure-ui-icons/plugin.js +2 -2
  29. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.d.ts +1 -1
  30. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.js +6 -10
  31. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/Course.d.ts +5 -15
  32. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/Course.js +4 -10
  33. package/es/rce/plugins/instructure_image/ImageEmbedOptions.d.ts +7 -0
  34. package/es/rce/plugins/instructure_image/ImageEmbedOptions.js +49 -9
  35. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.d.ts +1 -8
  36. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +13 -33
  37. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.d.ts +1 -2
  38. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +2 -1
  39. package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.js +1 -2
  40. package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +2 -4
  41. package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +10 -7
  42. package/es/rce/plugins/shared/ContentSelection.js +4 -7
  43. package/es/rce/plugins/shared/DimensionsInput/index.js +3 -3
  44. package/es/rce/plugins/shared/FixedContentTray.d.ts +7 -23
  45. package/es/rce/plugins/shared/FixedContentTray.js +7 -16
  46. package/es/rce/plugins/shared/ImageCropper/constants.d.ts +1 -1
  47. package/es/rce/plugins/shared/ImageCropper/constants.js +1 -1
  48. package/es/rce/plugins/shared/ImageCropper/controls/CustomNumberInput.js +1 -1
  49. package/es/rce/plugins/shared/PreviewIcon.js +1 -1
  50. package/es/rce/plugins/shared/ai_tools/aiicons.d.ts +3 -3
  51. package/es/rce/plugins/shared/ai_tools/aiicons.js +11 -11
  52. package/es/rce/plugins/shared/fileTypeUtils.js +1 -1
  53. package/es/rce/plugins/tinymce-a11y-checker/components/checker.js +7 -1
  54. package/es/rce/plugins/tinymce-a11y-checker/plugin.js +50 -52
  55. package/es/rce/plugins/tinymce-a11y-checker/utils/indicate.d.ts +1 -1
  56. package/es/rce/plugins/tinymce-a11y-checker/utils/indicate.js +1 -1
  57. package/es/rce/style.js +47 -45
  58. package/es/rcs/api.d.ts +4 -1
  59. package/es/rcs/api.js +9 -13
  60. package/es/translations/locales/ar.js +29 -5
  61. package/es/translations/locales/ca.js +32 -8
  62. package/es/translations/locales/cy.js +29 -5
  63. package/es/translations/locales/da-x-k12.js +29 -5
  64. package/es/translations/locales/da.js +29 -5
  65. package/es/translations/locales/de.js +29 -5
  66. package/es/translations/locales/en-AU-x-unimelb.js +29 -5
  67. package/es/translations/locales/en-GB-x-ukhe.js +29 -5
  68. package/es/translations/locales/en.js +20 -5
  69. package/es/translations/locales/en_AU.js +29 -5
  70. package/es/translations/locales/en_CA.js +29 -5
  71. package/es/translations/locales/en_CY.js +29 -5
  72. package/es/translations/locales/en_GB.js +29 -5
  73. package/es/translations/locales/es.js +29 -5
  74. package/es/translations/locales/es_ES.js +29 -5
  75. package/es/translations/locales/fa_IR.js +0 -3
  76. package/es/translations/locales/fi.js +29 -5
  77. package/es/translations/locales/fr.js +29 -5
  78. package/es/translations/locales/fr_CA.js +30 -6
  79. package/es/translations/locales/ga.js +46 -22
  80. package/es/translations/locales/hi.js +29 -5
  81. package/es/translations/locales/ht.js +29 -5
  82. package/es/translations/locales/hu.js +0 -6
  83. package/es/translations/locales/id.js +29 -5
  84. package/es/translations/locales/is.js +23 -5
  85. package/es/translations/locales/it.js +29 -5
  86. package/es/translations/locales/ja.js +29 -5
  87. package/es/translations/locales/mi.js +29 -5
  88. package/es/translations/locales/ms.js +29 -5
  89. package/es/translations/locales/nb-x-k12.js +29 -5
  90. package/es/translations/locales/nb.js +29 -5
  91. package/es/translations/locales/nl.js +29 -5
  92. package/es/translations/locales/nn.js +0 -6
  93. package/es/translations/locales/pl.js +29 -5
  94. package/es/translations/locales/pt.js +29 -5
  95. package/es/translations/locales/pt_BR.js +29 -5
  96. package/es/translations/locales/ru.js +29 -5
  97. package/es/translations/locales/sl.js +29 -5
  98. package/es/translations/locales/sv-x-k12.js +29 -5
  99. package/es/translations/locales/sv.js +29 -5
  100. package/es/translations/locales/th.js +29 -5
  101. package/es/translations/locales/uk_UA.js +0 -6
  102. package/es/translations/locales/vi.js +29 -5
  103. package/es/translations/locales/zh-Hans.js +29 -5
  104. package/es/translations/locales/zh-Hant.js +29 -5
  105. package/es/translations/locales/zh.js +29 -5
  106. package/es/translations/locales/zh_HK.js +29 -5
  107. package/es/util/contextHelper.d.ts +7 -0
  108. package/{testcafe/axe.test.js → es/util/contextHelper.js} +10 -21
  109. package/es/util/loadingPlaceholder.js +11 -11
  110. package/eslint.config.js +3 -25
  111. package/jest/jest-setup.js +27 -2
  112. package/jest.config.js +5 -1
  113. package/package.json +62 -85
  114. package/testcafe/RCEWrapper.test.js +0 -319
  115. package/testcafe/StatusBar.test.js +0 -108
  116. package/testcafe/enhanceUserContent.html +0 -58
  117. package/testcafe/enhanceUserContent.test.js +0 -44
  118. package/testcafe/entry.jsx +0 -77
  119. package/testcafe/testcafe.html +0 -14
  120. package/webpack.testcafe.config.js +0 -61
@@ -0,0 +1,87 @@
1
+ import _pt from "prop-types";
2
+ import React, { useRef, useEffect, useState, useCallback } from 'react';
3
+ import { createRoot } from 'react-dom/client';
4
+ import { Text } from '@instructure/ui-text';
5
+ import { View } from '@instructure/ui-view';
6
+ import { Flex } from '@instructure/ui-flex';
7
+ import { CondensedButton } from '@instructure/ui-buttons';
8
+ import { IconPlayLine } from '@instructure/ui-icons';
9
+ import formatMessage from '../format-message';
10
+ const YoutubeEmbedOverlay = ({
11
+ iframeElement,
12
+ height,
13
+ width
14
+ }) => {
15
+ const [showOverlay, setShowOverlay] = useState(true);
16
+ const containerRef = useRef(null);
17
+ useEffect(() => {
18
+ if (containerRef.current && iframeElement) {
19
+ if (width) {
20
+ containerRef.current.style.width = `${width}px`;
21
+ }
22
+ if (height) {
23
+ containerRef.current.style.height = `${height}px`;
24
+ }
25
+ containerRef.current.appendChild(iframeElement);
26
+ }
27
+ }, [height, iframeElement, width]);
28
+ const handleCloseOverlay = useCallback(() => {
29
+ setShowOverlay(false);
30
+ }, [setShowOverlay]);
31
+ return /*#__PURE__*/React.createElement(View, {
32
+ as: "div",
33
+ position: "relative",
34
+ display: "inline-block"
35
+ }, showOverlay && /*#__PURE__*/React.createElement(View, {
36
+ as: "div",
37
+ position: "absolute",
38
+ width: "100%",
39
+ height: "100%",
40
+ background: "primary",
41
+ themeOverride: {
42
+ backgroundPrimary: 'rgba(10, 71, 91, 0.65)'
43
+ },
44
+ overflowY: "hidden"
45
+ }, /*#__PURE__*/React.createElement(Flex, {
46
+ justifyItems: "center",
47
+ height: "100%"
48
+ }, /*#__PURE__*/React.createElement(Flex.Item, {
49
+ shouldShrink: true,
50
+ shouldGrow: true,
51
+ textAlign: "center"
52
+ }, /*#__PURE__*/React.createElement(Flex, {
53
+ justifyItems: "center",
54
+ margin: "0 0 small"
55
+ }, /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Text, {
56
+ color: "secondary-inverse",
57
+ weight: "bold"
58
+ }, formatMessage('This video may display YouTube ads.')))), /*#__PURE__*/React.createElement(Flex, {
59
+ justifyItems: "center",
60
+ margin: "0 0 medium"
61
+ }, /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(CondensedButton, {
62
+ "data-test-id": "youtube-migration-close-overlay",
63
+ color: "primary-inverse",
64
+ onClick: handleCloseOverlay
65
+ }, /*#__PURE__*/React.createElement(IconPlayLine, null), "\xA0", formatMessage('Continue to YouTube content'))))))), /*#__PURE__*/React.createElement("div", {
66
+ ref: containerRef
67
+ }));
68
+ };
69
+ YoutubeEmbedOverlay.propTypes = {
70
+ height: _pt.number.isRequired,
71
+ width: _pt.number.isRequired
72
+ };
73
+ export const createOverlay = iframes => {
74
+ iframes.forEach(iframe => {
75
+ const iframeElement = iframe;
76
+ const height = iframeElement.offsetHeight;
77
+ const width = iframeElement.offsetWidth;
78
+ const container = document.createElement('div');
79
+ container.setAttribute('data-test-id', 'youtube-migration-container');
80
+ iframe.replaceWith(container);
81
+ createRoot(container).render(/*#__PURE__*/React.createElement(YoutubeEmbedOverlay, {
82
+ iframeElement: iframeElement,
83
+ height: height,
84
+ width: width
85
+ }));
86
+ });
87
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -17,7 +17,12 @@
17
17
  */
18
18
 
19
19
  import formatMessage from 'format-message';
20
+ import generateId from 'format-message-generate-id/underscored_crc32';
20
21
  const ns = formatMessage.namespace();
22
+ ns.setup({
23
+ generateId,
24
+ missingTranslation: 'ignore'
25
+ });
21
26
  ns.addLocale = translations => {
22
27
  ns.setup({
23
28
  translations: {
package/es/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export declare const defaultConfiguration: {
16
16
  menubar: undefined;
17
17
  menu: undefined;
18
18
  toolbar: undefined;
19
+ color_map: string[];
19
20
  plugins: undefined;
20
21
  branding: boolean;
21
22
  browser_spellcheck: boolean;
@@ -25,7 +26,6 @@ export declare const defaultConfiguration: {
25
26
  language_load: boolean;
26
27
  language_url: string;
27
28
  toolbar_mode: string;
28
- toolbar_ticky: boolean;
29
29
  mobile: {
30
30
  theme: string;
31
31
  };
package/es/rce/RCE.d.ts CHANGED
@@ -16,7 +16,6 @@ export interface RCEPropTypes {
16
16
  autosave?: {
17
17
  enabled?: boolean;
18
18
  maxAge?: number;
19
- interval?: number;
20
19
  };
21
20
  /**
22
21
  * the protocol://domain:port for this RCE's canvas
package/es/rce/RCE.js CHANGED
@@ -16,7 +16,7 @@
16
16
  * with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
 
19
- import React, { forwardRef, useState } from 'react';
19
+ import React, { forwardRef, useEffect, useState } from 'react';
20
20
  import formatMessage from '../format-message';
21
21
  import RCEWrapper from './RCEWrapper';
22
22
  import { editorLanguage } from './editorLanguage';
@@ -69,15 +69,10 @@ const RCE = /*#__PURE__*/forwardRef(function RCE(props, rceRef) {
69
69
  locale: normalizeLocale(props.language)
70
70
  });
71
71
  });
72
- const [translations, setTranslations] = useState(() => {
72
+ const [isTranslationLoading, setIsTranslationLoading] = useState(true);
73
+ useEffect(() => {
73
74
  const locale = normalizeLocale(props.language);
74
- const p = getTranslations(locale).then(() => {
75
- setTranslations(true);
76
- }).catch(err => {
77
- console.error('Failed loading the language file for', locale, '\n Cause:', err);
78
- setTranslations(false);
79
- });
80
- return p;
75
+ getTranslations(locale).catch(err => console.error('Failed loading the language file for', locale, '\n Cause:', err)).finally(() => setIsTranslationLoading(false));
81
76
  });
82
77
 
83
78
  // some properties are only used on initialization
@@ -111,7 +106,7 @@ const RCE = /*#__PURE__*/forwardRef(function RCE(props, rceRef) {
111
106
  wrapInitCb(mirroredAttrs || {}, iProps.editorOptions);
112
107
  return iProps;
113
108
  });
114
- if (typeof translations !== 'boolean') {
109
+ if (isTranslationLoading) {
115
110
  return /*#__PURE__*/React.createElement(React.Fragment, null, formatMessage('Loading...'));
116
111
  } else {
117
112
  return /*#__PURE__*/React.createElement(RCEWrapper, Object.assign({
@@ -1,12 +1,10 @@
1
1
  export default instance;
2
2
  export type Features = {
3
- media_links_use_attachment_id: boolean;
4
3
  file_verifiers_for_quiz_links: boolean;
5
4
  };
6
5
  declare const instance: RCEGlobals;
7
6
  /**
8
7
  * @typedef {Object} Features
9
- * @property {boolean} media_links_use_attachment_id
10
8
  * @property {boolean} file_verifiers_for_quiz_links
11
9
  */
12
10
  declare class RCEGlobals {
@@ -20,7 +20,6 @@ const isEmpty = obj => Object.keys(obj).length === 0;
20
20
 
21
21
  /**
22
22
  * @typedef {Object} Features
23
- * @property {boolean} media_links_use_attachment_id
24
23
  * @property {boolean} file_verifiers_for_quiz_links
25
24
  */
26
25
 
@@ -7,11 +7,16 @@ interface ToolbarGroupSetting {
7
7
  name: string;
8
8
  items: string[];
9
9
  }
10
- type StatusBarFeature = 'ai_tools' | 'keyboard_shortcuts' | 'a11y_checker' | 'word_count' | 'html_view' | 'fullscreen' | 'resize_handle';
11
- export declare const RCEVariantValues: readonly ["full", "lite", "text-only", "text-block"];
10
+ type StatusBarFeature = 'ai_tools' | 'keyboard_shortcuts' | 'a11y_checker' | 'word_count' | 'html_view' | 'fullscreen' | 'resize_handle' | 'a11y_resize_handlers';
11
+ export declare const RCEVariantValues: readonly ["full", "lite", "text-only", "text-block", "block-content-editor"];
12
12
  export type RCEVariant = (typeof RCEVariantValues)[number];
13
+ export type StatusBarOptions = {
14
+ aiTextTools?: boolean;
15
+ isDesktop?: boolean;
16
+ a11yResizers?: boolean;
17
+ };
13
18
  export declare function getMenubarForVariant(variant: RCEVariant): MenuBarSpec;
14
19
  export declare function getMenuForVariant(variant: RCEVariant): MenusSpec;
15
20
  export declare function getToolbarForVariant(variant: RCEVariant, ltiToolFavorites?: string[]): ToolbarGroupSetting[];
16
- export declare function getStatusBarFeaturesForVariant(variant: RCEVariant, ai_text_tools?: boolean): StatusBarFeature[];
21
+ export declare function getStatusBarFeaturesForVariant(variant: RCEVariant, options?: StatusBarOptions): StatusBarFeature[];
17
22
  export {};
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2024 - present Instructure, Inc.
2
+ * Copyright (C) 2025 - present Instructure, Inc.
3
3
  *
4
4
  * This file is part of Canvas.
5
5
  *
@@ -21,7 +21,7 @@ import formatMessage from '../format-message';
21
21
 
22
22
  // copied from node_modules/tinymce/tinymce.d.ts:1187
23
23
 
24
- export const RCEVariantValues = ['full', 'lite', 'text-only', 'text-block'];
24
+ export const RCEVariantValues = ['full', 'lite', 'text-only', 'text-block', 'block-content-editor'];
25
25
  export function getMenubarForVariant(variant) {
26
26
  if (variant === 'full') {
27
27
  return 'edit view insert format tools table';
@@ -101,6 +101,24 @@ export function getToolbarForVariant(variant, ltiToolFavorites = []) {
101
101
  items: ['removeformat', 'instructure_equation']
102
102
  }];
103
103
  }
104
+ if (variant === 'block-content-editor') {
105
+ return [{
106
+ name: formatMessage('Styles'),
107
+ items: ['fontsizeselect', 'formatselect']
108
+ }, {
109
+ name: formatMessage('Formatting'),
110
+ items: ['bold', 'italic', 'underline', 'instructure_color', 'inst_subscript', 'inst_superscript']
111
+ }, {
112
+ name: formatMessage('Content'),
113
+ items: ['instructure_links', 'instructure_documents']
114
+ }, {
115
+ name: formatMessage('Alignment and Lists'),
116
+ items: ['align', 'bullist', 'inst_indent', 'inst_outdent']
117
+ }, {
118
+ name: formatMessage('Miscellaneous'),
119
+ items: ['removeformat', 'instructure_equation']
120
+ }];
121
+ }
104
122
  return [{
105
123
  name: formatMessage('Styles'),
106
124
  items: ['fontsizeselect', 'formatselect']
@@ -121,16 +139,24 @@ export function getToolbarForVariant(variant, ltiToolFavorites = []) {
121
139
  items: ['removeformat', 'table', 'instructure_equation', 'instructure_media_embed']
122
140
  }];
123
141
  }
124
- export function getStatusBarFeaturesForVariant(variant, ai_text_tools = false) {
125
- if (variant === 'lite' || variant === 'text-only') {
126
- return ['keyboard_shortcuts', 'a11y_checker', 'word_count'];
127
- }
142
+ const DESKTOP_FEATURES = ['keyboard_shortcuts', 'a11y_checker', 'word_count'];
143
+ const MOBILE_FEATURES = ['a11y_checker', 'word_count'];
144
+ const EXTENDED_FEATURES = ['html_view', 'fullscreen', 'resize_handle'];
145
+ const A11Y_RESIZERS = ['a11y_resize_handlers'];
146
+ export function getStatusBarFeaturesForVariant(variant, options = {
147
+ aiTextTools: false,
148
+ isDesktop: true,
149
+ a11yResizers: false
150
+ }) {
128
151
  if (variant === 'text-block') {
129
152
  return [];
130
153
  }
131
- const full_features = ['keyboard_shortcuts', 'a11y_checker', 'word_count', 'html_view', 'fullscreen', 'resize_handle'];
132
- if (ai_text_tools) {
133
- full_features.push('ai_tools');
154
+ if (variant === 'block-content-editor') {
155
+ return ['keyboard_shortcuts', 'word_count'];
156
+ }
157
+ const platformFeatures = options.isDesktop ? DESKTOP_FEATURES : MOBILE_FEATURES;
158
+ if (variant === 'lite' || variant === 'text-only') {
159
+ return platformFeatures;
134
160
  }
135
- return full_features;
161
+ return [...platformFeatures, ...EXTENDED_FEATURES, ...(options.a11yResizers ? A11Y_RESIZERS : []), ...(options.aiTextTools ? ['ai_tools'] : [])];
136
162
  }
@@ -13,7 +13,6 @@ interface RCEWrapperProps {
13
13
  autosave?: {
14
14
  enabled?: boolean;
15
15
  maxAge?: number;
16
- interval?: number;
17
16
  };
18
17
  canvasOrigin: string;
19
18
  defaultContent?: string;
@@ -75,6 +74,7 @@ declare class RCEWrapper extends React.Component<RCEWrapperProps, RCEWrapperStat
75
74
  _showOnFocusButton?: HTMLElement;
76
75
  _statusBarId: string;
77
76
  _textareaEl?: HTMLTextAreaElement;
77
+ _effectiveContainingContext: RCETrayProps['containingContext'];
78
78
  AIToolsTray?: ReactNode;
79
79
  editor: TinyMCEEditor | null;
80
80
  initialContent?: string;
@@ -191,7 +191,7 @@ declare class RCEWrapper extends React.Component<RCEWrapperProps, RCEWrapperStat
191
191
  maxMruTools: import("prop-types").Requireable<number>;
192
192
  }>>;
193
193
  ai_text_tools: import("prop-types").Requireable<boolean>;
194
- variant: import("prop-types").Requireable<"full" | "lite" | "text-only" | "text-block">;
194
+ variant: import("prop-types").Requireable<"full" | "lite" | "text-only" | "text-block" | "block-content-editor">;
195
195
  };
196
196
  static defaultProps: {
197
197
  trayProps: null;
@@ -214,7 +214,6 @@ declare class RCEWrapper extends React.Component<RCEWrapperProps, RCEWrapperStat
214
214
  new_math_equation_handling: unknown;
215
215
  explicit_latex_typesetting: unknown;
216
216
  rce_transform_loaded_content: unknown;
217
- media_links_use_attachment_id: unknown;
218
217
  file_verifiers_for_quiz_links: unknown;
219
218
  rce_find_replace: unknown;
220
219
  consolidated_media_player: unknown;
@@ -348,7 +347,6 @@ declare class RCEWrapper extends React.Component<RCEWrapperProps, RCEWrapperStat
348
347
  type: string;
349
348
  content: string;
350
349
  };
351
- setFocusAbilityForHeader: (focusable: boolean) => void;
352
350
  componentWillUnmount(): void;
353
351
  wrapOptions(options?: {}): {
354
352
  readonly: boolean | undefined;
@@ -379,13 +377,13 @@ declare class RCEWrapper extends React.Component<RCEWrapperProps, RCEWrapperStat
379
377
  auto_focus: boolean;
380
378
  body_class: string;
381
379
  directionality: string;
380
+ color_map: string[];
382
381
  branding: boolean;
383
382
  browser_spellcheck: boolean;
384
383
  convert_urls: boolean;
385
384
  font_formats: string;
386
385
  language_load: boolean;
387
386
  language_url: string;
388
- toolbar_ticky: boolean;
389
387
  mobile: {
390
388
  theme: string;
391
389
  };