@crystallize/design-system 1.11.7 → 1.13.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 (84) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/draggable-block-menu-KKHDNKJA.svg +1 -0
  3. package/dist/index.css +565 -1025
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +538 -517
  6. package/dist/index.mjs +419 -398
  7. package/package.json +22 -23
  8. package/src/button/Button.stories.tsx +1 -0
  9. package/src/card/card.stories.tsx +1 -0
  10. package/src/checkbox/checkbox.stories.tsx +1 -1
  11. package/src/checkbox/checkbox.tsx +1 -1
  12. package/src/colors/Colors.stories.tsx +3 -3
  13. package/src/dialog/config.tsx +1 -1
  14. package/src/dialog/index.tsx +1 -1
  15. package/src/dropdown-menu/dropdown-menu-item.tsx +2 -2
  16. package/src/dropdown-menu/dropdown-menu-label.tsx +1 -1
  17. package/src/icon-button/IconButton.stories.tsx +1 -0
  18. package/src/iconography/Icon.stories.tsx +1 -0
  19. package/src/inline-radio/inline-radio.stories.tsx +3 -3
  20. package/src/inline-radio/inline-radio.tsx +2 -2
  21. package/src/input/input.tsx +1 -1
  22. package/src/input-with-label/input-with-label.tsx +1 -1
  23. package/src/label/label.stories.tsx +1 -0
  24. package/src/progress/Progress.stories.tsx +2 -1
  25. package/src/progress/progress.tsx +1 -1
  26. package/src/radio/radio.stories.tsx +1 -1
  27. package/src/radio/radio.tsx +1 -1
  28. package/src/rich-text-editor/model/crystallize-to-lexical.ts +4 -3
  29. package/src/rich-text-editor/model/parse-initial-state.test.ts +48 -0
  30. package/src/rich-text-editor/model/parse-initial-state.ts +20 -0
  31. package/src/rich-text-editor/plugins/ActionsPlugin/index.css +3 -0
  32. package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +1 -2
  33. package/src/rich-text-editor/plugins/AutoLinkPlugin/index.tsx +1 -1
  34. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +6 -2
  35. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +10 -6
  36. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.css +32 -17
  37. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx +3 -4
  38. package/src/rich-text-editor/plugins/DimensionsDetectorPlugin/index.tsx +49 -0
  39. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.css +14 -14
  40. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.tsx +4 -4
  41. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.css +87 -21
  42. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx +11 -17
  43. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.css +10 -2
  44. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +17 -17
  45. package/src/rich-text-editor/plugins/LinkPlugin/index.tsx +1 -1
  46. package/src/rich-text-editor/plugins/ListMaxIndentLevelPlugin/index.ts +10 -21
  47. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.css +6 -0
  48. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +2 -2
  49. package/src/rich-text-editor/plugins/ToolbarPlugin/index.css +115 -0
  50. package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +57 -78
  51. package/src/rich-text-editor/plugins/ToolbarPlugin/insert-table.tsx +5 -5
  52. package/src/rich-text-editor/rich-text-editor-icons.css +213 -0
  53. package/src/rich-text-editor/rich-text-editor.css +33 -913
  54. package/src/rich-text-editor/rich-text-editor.stories.tsx +24 -0
  55. package/src/rich-text-editor/rich-text-editor.tsx +13 -27
  56. package/src/rich-text-editor/themes/CrystallizeRTEditorTheme.ts +1 -1
  57. package/src/rich-text-editor/ui/LinkPreview.tsx +7 -8
  58. package/src/rich-text-editor/utils/getSelectedNode.ts +4 -5
  59. package/src/rich-text-editor/utils/point.ts +4 -7
  60. package/src/rich-text-editor/utils/rect.ts +18 -41
  61. package/src/rich-text-editor/utils/url.ts +1 -2
  62. package/src/select/select-root.tsx +1 -1
  63. package/src/select/select.stories.tsx +1 -1
  64. package/src/select/select.ts +0 -1
  65. package/src/slider/Slider.stories.tsx +2 -1
  66. package/src/slider/slider.tsx +2 -2
  67. package/src/spinner/Spinner.stories.tsx +1 -0
  68. package/src/spinner/index.tsx +1 -1
  69. package/src/tag/Tag.stories.tsx +1 -0
  70. package/dist/camera-CR7D2PNH.svg +0 -1
  71. package/dist/clipboard-OSEFDF25.svg +0 -1
  72. package/dist/gear-ICMT4NTP.svg +0 -1
  73. package/dist/journal-code-XUT44HDV.svg +0 -1
  74. package/dist/lock-WCYOZOHW.svg +0 -1
  75. package/dist/lock-fill-JZSKOSHK.svg +0 -1
  76. package/dist/pencil-fill-STFSC26F.svg +0 -1
  77. package/dist/plug-HGGGEVS3.svg +0 -1
  78. package/dist/plug-fill-OTG3U4TN.svg +0 -1
  79. package/src/rich-text-editor/hooks/useReport.ts +0 -64
  80. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.css +0 -14
  81. package/src/rich-text-editor/ui/LinkPreview.css +0 -57
  82. package/src/rich-text-editor/utils/isMobileWidth.ts +0 -7
  83. package/src/rich-text-editor/utils/joinClasses.ts +0 -13
  84. package/src/rich-text-editor/utils/swipe.ts +0 -127
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crystallize/design-system",
3
- "version": "1.11.7",
3
+ "version": "1.13.0",
4
4
  "types": "./dist/index.d.ts",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -58,39 +58,38 @@
58
58
  "@faker-js/faker": "7.6.0",
59
59
  "@ianvs/prettier-plugin-sort-imports": "^3.7.1",
60
60
  "@mdx-js/react": "^2.2.1",
61
- "@storybook/addon-actions": "7.0.0-beta.14",
62
- "@storybook/addon-backgrounds": "7.0.0-beta.14",
63
- "@storybook/addon-docs": "7.0.0-beta.14",
64
- "@storybook/addon-essentials": "7.0.0-beta.14",
65
- "@storybook/addon-highlight": "7.0.0-beta.14",
66
- "@storybook/addon-interactions": "7.0.0-beta.14",
67
- "@storybook/addon-links": "7.0.0-beta.14",
68
- "@storybook/addon-measure": "7.0.0-beta.14",
69
- "@storybook/addon-outline": "7.0.0-beta.14",
61
+ "@storybook/addon-actions": "7.0.7",
62
+ "@storybook/addon-backgrounds": "7.0.7",
63
+ "@storybook/addon-docs": "7.0.7",
64
+ "@storybook/addon-essentials": "7.0.7",
65
+ "@storybook/addon-highlight": "7.0.7",
66
+ "@storybook/addon-interactions": "7.0.7",
67
+ "@storybook/addon-links": "7.0.7",
68
+ "@storybook/addon-measure": "7.0.7",
69
+ "@storybook/addon-outline": "7.0.7",
70
70
  "@storybook/addons": "^6.5.15",
71
- "@storybook/react": "7.0.0-beta.14",
72
- "@storybook/react-vite": "7.0.0-beta.14",
73
- "@storybook/testing-library": "^0.0.13",
74
- "@storybook/theming": "7.0.0-beta.14",
75
- "@testing-library/jest-dom": "^5.16.4",
76
- "@testing-library/react": "^12.0.0",
77
- "@testing-library/user-event": "^14.4.3",
71
+ "@storybook/react": "7.0.7",
72
+ "@storybook/react-vite": "7.0.7",
73
+ "@storybook/theming": "7.0.7",
74
+ "@testing-library/jest-dom": "5.16.4",
75
+ "@testing-library/react": "12.0.0",
76
+ "@testing-library/user-event": "14.4.3",
78
77
  "@types/prettier": "2.7.2",
79
78
  "@types/react": "17.0.1",
80
79
  "@types/react-dom": "17.0.1",
81
- "@types/testing-library__jest-dom": "^5.14.5",
80
+ "@types/testing-library__jest-dom": "5.14.5",
82
81
  "@vitejs/plugin-react": "^3.0.1",
83
82
  "concurrently": "^7.6.0",
84
83
  "hex-rgb": "4.3.0",
85
84
  "postcss": "^8.4.21",
86
- "storybook": "7.0.0-beta.14",
85
+ "storybook": "7.0.7",
87
86
  "storybook-addon-designs": "^6.3.1",
88
87
  "storybook-dark-mode": "^2.0.5",
89
88
  "tailwindcss": "^3.3.0",
90
89
  "tsup": "^6.5.0",
91
- "typescript": "^4.9.4",
92
- "vite": "^4.2.1",
93
- "vitest": "^0.30.1",
90
+ "typescript": "4.9.4",
91
+ "vite": "4.3.4",
92
+ "vitest": "0.30.1",
94
93
  "tsconfig": "0.0.0"
95
94
  },
96
95
  "keywords": [
@@ -116,7 +115,7 @@
116
115
  "build:storybook": "storybook build -s public",
117
116
  "build:tw": "tailwindcss --content ./src/**/*.tsx,!./src/**/*.stories.tsx -c ./tailwind.config.cjs -i src/index.css -o dist/index.css --minify",
118
117
  "build:tsup": "tsup src/index.ts --format esm,cjs --dts",
119
- "build": "pnpm build:tw && pnpm build:tsup && pnpm build:storybook",
118
+ "build": "pnpm build:tw && pnpm build:tsup",
120
119
  "dev:tw": "tailwindcss --content ./src/**/*.tsx,!./src/**/*.stories.tsx -c ./tailwind.config.cjs -i src/index.css -o dist/index.css --watch & tsup src/index.ts --format esm --dts --watch",
121
120
  "dev:tsup": "tsup src/index.ts --format esm --dts --watch",
122
121
  "dev:storybook": "storybook dev -p 6006 --no-open -s public",
@@ -1,4 +1,5 @@
1
1
  import type { StoryObj, Meta } from '@storybook/react';
2
+
2
3
  import { Button } from '.';
3
4
 
4
5
  const meta: Meta<typeof Button> = {
@@ -1,4 +1,5 @@
1
1
  import type { StoryObj, Meta } from '@storybook/react';
2
+
2
3
  import { Card } from '.';
3
4
 
4
5
  const meta: Meta<typeof Card> = {
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
2
1
  import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
3
 
4
4
  import { Label } from '../label';
5
5
  import { Checkbox } from './checkbox';
@@ -1,5 +1,5 @@
1
- import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
2
1
  import { ComponentProps, forwardRef } from 'react';
2
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
3
 
4
4
  import './checkbox.css';
5
5
 
@@ -1,10 +1,10 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
2
1
  import { cx } from 'class-variance-authority';
3
2
  import { useDarkMode } from 'storybook-dark-mode';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
4
 
5
- import rawColors from './colors.json';
6
- import colorPairing from './color-pairing.json';
7
5
  import colorDefaults from './color-defaults.json';
6
+ import colorPairing from './color-pairing.json';
7
+ import rawColors from './colors.json';
8
8
  import type { Color, ColorName, Colors } from './types';
9
9
 
10
10
  const meta: Meta = {
@@ -1,6 +1,6 @@
1
1
  import { unmountComponentAtNode, render as DOMRender } from 'react-dom';
2
- import { ConfirmDialog } from './confirm-dialog';
3
2
 
3
+ import { ConfirmDialog } from './confirm-dialog';
4
4
  import { destroyFns } from './destroyFns';
5
5
  import type { ConfigUpdate, DialogFuncProps } from './types';
6
6
 
@@ -1,7 +1,7 @@
1
+ import { confirm, withWarning, withConfirm, withDialog, withError, withInfo } from './config';
1
2
  import { destroyFns } from './destroyFns';
2
3
  import { DialogBase } from './dialog';
3
4
  import type { DialogFuncProps } from './types';
4
- import { confirm, withWarning, withConfirm, withDialog, withError, withInfo } from './config';
5
5
 
6
6
  type DialogType = typeof DialogBase & DialogFuncProps;
7
7
 
@@ -1,6 +1,6 @@
1
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
- import { cx } from 'class-variance-authority';
3
1
  import type { ReactNode } from 'react';
2
+ import { cx } from 'class-variance-authority';
3
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
4
4
 
5
5
  type DropdownMenuItemProps = DropdownMenuPrimitive.MenuItemProps & {
6
6
  children: ReactNode;
@@ -1,5 +1,5 @@
1
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
1
  import type { ReactNode } from 'react';
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
3
 
4
4
  type DropdownMenuLabelProps = {
5
5
  children: ReactNode;
@@ -1,4 +1,5 @@
1
1
  import type { StoryObj, Meta } from '@storybook/react';
2
+
2
3
  import { IconButton } from '.';
3
4
  import { Card } from '../card';
4
5
  import { Icon } from '../iconography';
@@ -1,4 +1,5 @@
1
1
  import type { StoryObj, Meta } from '@storybook/react';
2
+
2
3
  import { Icon } from '.';
3
4
  import { Card } from '../card';
4
5
 
@@ -1,9 +1,9 @@
1
1
  import { useState } from 'react';
2
- import { InlineRadio } from './inline-radio';
3
- import { Icon } from '../iconography';
4
-
5
2
  import type { Meta, StoryObj } from '@storybook/react';
6
3
 
4
+ import { Icon } from '../iconography';
5
+ import { InlineRadio } from './inline-radio';
6
+
7
7
  const meta: Meta<typeof InlineRadio.Group> = {
8
8
  title: 'Components/InlineRadio',
9
9
  component: InlineRadio.Group,
@@ -1,6 +1,6 @@
1
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
2
- import { cx, cva, VariantProps } from 'class-variance-authority';
3
1
  import type { ComponentProps } from 'react';
2
+ import { cx, cva, VariantProps } from 'class-variance-authority';
3
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
4
4
 
5
5
  import './inline-radio.css';
6
6
 
@@ -1,5 +1,5 @@
1
- import { cva, VariantProps } from 'class-variance-authority';
2
1
  import { ComponentPropsWithRef, forwardRef } from 'react';
2
+ import { cva, VariantProps } from 'class-variance-authority';
3
3
 
4
4
  import './input.css';
5
5
 
@@ -1,9 +1,9 @@
1
1
  import { ComponentPropsWithoutRef, ComponentPropsWithRef, forwardRef, ReactNode } from 'react';
2
2
  import { cva, cx, VariantProps } from 'class-variance-authority';
3
3
 
4
+ import { Triangle } from '../iconography/triangle';
4
5
  import { Input } from '../input';
5
6
  import { Label } from '../label';
6
- import { Triangle } from '../iconography/triangle';
7
7
 
8
8
  const inputWithLabelStyles = cva(['c-input-with-label'], {
9
9
  variants: {
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
+
2
3
  import { Label } from './label';
3
4
 
4
5
  const meta: Meta<typeof Label> = {
@@ -1,5 +1,6 @@
1
- import type { StoryObj, Meta } from '@storybook/react';
2
1
  import { useEffect, useState } from 'react';
2
+ import type { StoryObj, Meta } from '@storybook/react';
3
+
3
4
  import { Progress } from '.';
4
5
 
5
6
  const meta: Meta<typeof Progress> = {
@@ -1,5 +1,5 @@
1
- import * as ProgressPrimitives from '@radix-ui/react-progress';
2
1
  import { cx } from 'class-variance-authority';
2
+ import * as ProgressPrimitives from '@radix-ui/react-progress';
3
3
 
4
4
  import './progress.css';
5
5
 
@@ -1,8 +1,8 @@
1
1
  import { useState } from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
 
4
- import { Radio } from './radio';
5
4
  import { Label } from '../label';
5
+ import { Radio } from './radio';
6
6
 
7
7
  const meta: Meta<typeof Radio.Group> = {
8
8
  title: 'Components/Radio',
@@ -1,5 +1,5 @@
1
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
2
1
  import type { ComponentProps } from 'react';
2
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
3
3
 
4
4
  import './radio.css';
5
5
 
@@ -15,13 +15,12 @@ import { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';
15
15
  import { $createTableCellNode, $createTableNode, $createTableRowNode } from '@lexical/table';
16
16
 
17
17
  import type { CrystallizeRichTextNode, CrystallizeRichText } from '../types/crystallize-rich-text-types';
18
+ import { parseInitialState } from './parse-initial-state';
18
19
 
19
20
  export function composeInitialState({ richText }: { richText: CrystallizeRichText }) {
20
21
  return function setLexicalState() {
21
22
  const root = $getRoot();
22
23
 
23
- const richTextArray = Array.isArray(richText) ? richText : [richText];
24
-
25
24
  function handleNode({
26
25
  crystallizeContentNode,
27
26
  lexicalParent,
@@ -196,7 +195,9 @@ export function composeInitialState({ richText }: { richText: CrystallizeRichTex
196
195
  }
197
196
  }
198
197
 
199
- richTextArray.forEach(crystallizeContentNode => handleNode({ crystallizeContentNode, lexicalParent: root }));
198
+ parseInitialState({ richText }).forEach(crystallizeContentNode =>
199
+ handleNode({ crystallizeContentNode, lexicalParent: root }),
200
+ );
200
201
  };
201
202
  }
202
203
 
@@ -0,0 +1,48 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import type { CrystallizeRichText } from '../rich-text-editor';
4
+ import { parseInitialState } from './parse-initial-state';
5
+
6
+ describe('RichTextEditor parseInitialState', () => {
7
+ it('ensures that the initial state is an array', async () => {
8
+ expect(
9
+ parseInitialState({
10
+ richText: {
11
+ kind: 'block',
12
+ type: 'paragraph',
13
+ textContent: 'hello',
14
+ },
15
+ }),
16
+ ).toEqual([
17
+ {
18
+ kind: 'block',
19
+ type: 'paragraph',
20
+ textContent: 'hello',
21
+ },
22
+ ]);
23
+ });
24
+
25
+ it('ensures that all root nodes are block elements', async () => {
26
+ expect(
27
+ parseInitialState({
28
+ richText: [
29
+ {
30
+ kind: 'inline',
31
+ textContent: 'hello',
32
+ },
33
+ ],
34
+ }),
35
+ ).toEqual([
36
+ {
37
+ kind: 'block',
38
+ type: 'paragraph',
39
+ children: [
40
+ {
41
+ kind: 'inline',
42
+ textContent: 'hello',
43
+ },
44
+ ],
45
+ } as CrystallizeRichText,
46
+ ]);
47
+ });
48
+ });
@@ -0,0 +1,20 @@
1
+ import type { CrystallizeRichText, CrystallizeRichTextNode } from '../types/crystallize-rich-text-types';
2
+
3
+ export function parseInitialState({ richText }: { richText: CrystallizeRichText }): CrystallizeRichTextNode[] {
4
+ let richTextArray = Array.isArray(richText) ? richText : [richText];
5
+
6
+ // Ensure all root items are block elements
7
+ richTextArray = richTextArray.map(rootNode => {
8
+ if (!rootNode.kind || rootNode.kind === 'inline') {
9
+ return {
10
+ type: 'paragraph',
11
+ kind: 'block',
12
+ children: [rootNode],
13
+ };
14
+ }
15
+
16
+ return rootNode;
17
+ });
18
+
19
+ return richTextArray;
20
+ }
@@ -0,0 +1,3 @@
1
+ .c-rte-actions-plugin {
2
+ @apply z-50 flex items-center;
3
+ }
@@ -38,8 +38,7 @@ export default function ActionsPlugin({
38
38
  const actionMenuAnchorRef = useRef<HTMLDivElement>(null);
39
39
 
40
40
  return (
41
- <div ref={actionMenuAnchorRef} className="z-50 flex items-center ">
42
- <div></div>
41
+ <div ref={actionMenuAnchorRef} className="c-rte-actions-plugin">
43
42
  <ActionMenu container={actionMenuAnchorRef.current}>
44
43
  {!prepend
45
44
  ? null
@@ -6,8 +6,8 @@
6
6
  *
7
7
  */
8
8
 
9
- import { AutoLinkPlugin } from '@lexical/react/LexicalAutoLinkPlugin';
10
9
  import * as React from 'react';
10
+ import { AutoLinkPlugin } from '@lexical/react/LexicalAutoLinkPlugin';
11
11
 
12
12
  const URL_MATCHER =
13
13
  /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
@@ -57,8 +57,12 @@ export function CopyButton({ editor, getCodeDOMNode }: Props) {
57
57
  }
58
58
 
59
59
  return (
60
- <button className="menu-item" onClick={handleClick} aria-label={tr('actionCopyCode')}>
61
- {isCopyCompleted ? <i className="format success" /> : <i className="format copy" />}
60
+ <button className="c-rte-code-button" onClick={handleClick} aria-label={tr('actionCopyCode')}>
61
+ {isCopyCompleted ? (
62
+ <i className="c-rte-code-button__icon c-rte-icon-success" />
63
+ ) : (
64
+ <i className="c-rte-code-button__icon c-rte-icon-copy" />
65
+ )}
62
66
  </button>
63
67
  );
64
68
  }
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- import './index.css';
8
+
9
9
  import * as React from 'react';
10
10
  import { useState } from 'react';
11
11
  import { $getNearestNodeFromDOMNode, LexicalEditor } from 'lexical';
@@ -98,7 +98,7 @@ export function PrettierButton({ lang, editor, getCodeDOMNode }: Props) {
98
98
  /**
99
99
  * Remove EOF from prettier output. This is useful when
100
100
  * using prettier on files, but becomes weird when the code
101
- * is embedded within a larger portion of text.
101
+ * is embedded within a larger portion of text (like we do)
102
102
  */
103
103
  parsed = parsed.replace(/[\r\n]+$/, '');
104
104
 
@@ -133,17 +133,21 @@ export function PrettierButton({ lang, editor, getCodeDOMNode }: Props) {
133
133
  }
134
134
 
135
135
  return (
136
- <div className="prettier-wrapper">
136
+ <div className="c-rte-prettier-wrapper">
137
137
  <button
138
- className="menu-item"
138
+ className="c-rte-code-button"
139
139
  onClick={handleClick}
140
140
  onMouseEnter={handleMouseEnter}
141
141
  onMouseLeave={handleMouseLeave}
142
142
  aria-label={tr('actionFormatCode')}
143
143
  >
144
- {syntaxError ? <i className="format prettier-error" /> : <i className="format prettier" />}
144
+ {syntaxError ? (
145
+ <i className="c-rte-code-button__icon c-rte-icon-prettier-error" />
146
+ ) : (
147
+ <i className="c-rte-code-button__icon c-rte-icon-prettier" />
148
+ )}
145
149
  </button>
146
- {tipsVisible ? <pre className="code-error-tips">{syntaxError}</pre> : null}
150
+ {tipsVisible ? <pre className="c-rte-code-error-tips">{syntaxError}</pre> : null}
147
151
  </div>
148
152
  );
149
153
  }
@@ -1,4 +1,4 @@
1
- .code-action-menu-container {
1
+ .c-rte-code-action-menu-container {
2
2
  height: 35.8px;
3
3
  font-size: 10px;
4
4
  color: rgba(0, 0, 0, 0.5);
@@ -9,11 +9,11 @@
9
9
  user-select: none;
10
10
  }
11
11
 
12
- .code-action-menu-container .code-highlight-language {
12
+ .c-rte-code-highlight-language {
13
13
  margin-right: 4px;
14
14
  }
15
15
 
16
- .code-action-menu-container button.menu-item {
16
+ .c-rte-code-button {
17
17
  border: 1px solid transparent;
18
18
  border-radius: 4px;
19
19
  padding: 4px;
@@ -24,23 +24,38 @@
24
24
  align-items: center;
25
25
  color: rgba(0, 0, 0, 0.5);
26
26
  text-transform: uppercase;
27
- }
28
27
 
29
- .code-action-menu-container button.menu-item i.format {
30
- height: 16px;
31
- width: 16px;
32
- opacity: 0.6;
33
- display: flex;
34
- color: rgba(0, 0, 0, 0.5);
35
- background-size: contain;
28
+ &:hover {
29
+ border: 1px solid rgba(0, 0, 0, 0.3);
30
+ opacity: 0.9;
31
+ }
32
+
33
+ &:active {
34
+ background-color: rgba(223, 232, 250);
35
+ border: 1px solid rgba(0, 0, 0, 0.45);
36
+ }
37
+
38
+ &__icon {
39
+ height: 16px;
40
+ width: 16px;
41
+ opacity: 0.6;
42
+ display: flex;
43
+ color: rgba(0, 0, 0, 0.5);
44
+ background-size: contain;
45
+ }
36
46
  }
37
47
 
38
- .code-action-menu-container button.menu-item:hover {
39
- border: 1px solid rgba(0, 0, 0, 0.3);
40
- opacity: 0.9;
48
+ .c-rte-prettier-wrapper {
49
+ position: relative;
41
50
  }
42
51
 
43
- .code-action-menu-container button.menu-item:active {
44
- background-color: rgba(223, 232, 250);
45
- border: 1px solid rgba(0, 0, 0, 0.45);
52
+ .c-rte-code-error-tips {
53
+ padding: 5px;
54
+ border-radius: 4px;
55
+ color: #fff;
56
+ background: #222;
57
+ margin-top: 4px;
58
+ position: absolute;
59
+ top: 26px;
60
+ right: 0;
46
61
  }
@@ -6,7 +6,6 @@
6
6
  *
7
7
  */
8
8
 
9
- import './index.css';
10
9
  import { useEffect, useRef, useState } from 'react';
11
10
  import { $getNearestNodeFromDOMNode } from 'lexical';
12
11
  import { createPortal } from 'react-dom';
@@ -119,8 +118,8 @@ function CodeActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement }): J
119
118
  return (
120
119
  <>
121
120
  {isShown ? (
122
- <div className="code-action-menu-container" style={{ ...position }}>
123
- <div className="code-highlight-language">{codeFriendlyName}</div>
121
+ <div className="c-rte-code-action-menu-container" style={{ ...position }}>
122
+ <div className="c-rte-code-highlight-language">{codeFriendlyName}</div>
124
123
  <CopyButton editor={editor} getCodeDOMNode={getCodeDOMNode} />
125
124
  {canBePrettier(normalizedLang) ? (
126
125
  <PrettierButton editor={editor} getCodeDOMNode={getCodeDOMNode} lang={normalizedLang} />
@@ -139,7 +138,7 @@ function getMouseInfo(event: MouseEvent): {
139
138
 
140
139
  if (target && target instanceof HTMLElement) {
141
140
  const codeDOMNode = target.closest<HTMLElement>('code.CrystallizeRTEditorTheme__code');
142
- const isOutside = !(codeDOMNode || target.closest<HTMLElement>('div.code-action-menu-container'));
141
+ const isOutside = !(codeDOMNode || target.closest<HTMLElement>('div.c-rte-code-action-menu-container'));
143
142
 
144
143
  return { codeDOMNode, isOutside };
145
144
  } else {
@@ -0,0 +1,49 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+
3
+ type Dimensions = {
4
+ isSmallWidth: boolean;
5
+ width: number;
6
+ };
7
+
8
+ type DimensionDetectorPluginProps = {
9
+ onChange: (p: Dimensions) => void;
10
+ };
11
+
12
+ export function DimensionDetectorPlugin({ onChange }: DimensionDetectorPluginProps) {
13
+ const [dimensions, setDimensions] = useState<Dimensions>();
14
+ const ref = useRef<HTMLDivElement | null>(null);
15
+
16
+ useEffect(() => {
17
+ if (ref.current) {
18
+ const el = ref.current;
19
+ const resizeObserver = new ResizeObserver(entries => {
20
+ const [first] = entries;
21
+ if (first) {
22
+ const [contentBox] = first.contentBoxSize;
23
+ if (contentBox) {
24
+ const width = contentBox.inlineSize;
25
+ setDimensions({
26
+ width,
27
+ /**
28
+ * 600 is (currently) the point before action button crashes with
29
+ * the rest of the toolbar buttons.
30
+ */
31
+ isSmallWidth: width < 600,
32
+ });
33
+ }
34
+ }
35
+ });
36
+ resizeObserver.observe(el);
37
+
38
+ return () => resizeObserver.disconnect();
39
+ }
40
+ }, []);
41
+
42
+ useEffect(() => {
43
+ if (dimensions) {
44
+ onChange(dimensions);
45
+ }
46
+ }, [dimensions, onChange]);
47
+
48
+ return <div ref={ref} style={{ height: 1, marginTop: -1 }} />;
49
+ }
@@ -1,4 +1,4 @@
1
- .draggable-block-menu {
1
+ .c-rte-draggable-block-menu {
2
2
  border-radius: 4px;
3
3
  padding: 2px 1px;
4
4
  cursor: grab;
@@ -7,24 +7,24 @@
7
7
  left: 0;
8
8
  top: 0;
9
9
  will-change: transform;
10
- }
11
10
 
12
- .draggable-block-menu .icon {
13
- width: 16px;
14
- height: 16px;
15
- opacity: 0.3;
16
- background-image: url(../../images/icons/draggable-block-menu.svg);
17
- }
11
+ &:active {
12
+ cursor: grabbing;
13
+ }
18
14
 
19
- .draggable-block-menu:active {
20
- cursor: grabbing;
21
- }
15
+ &:hover {
16
+ background-color: #efefef;
17
+ }
22
18
 
23
- .draggable-block-menu:hover {
24
- background-color: #efefef;
19
+ &__icon {
20
+ width: 16px;
21
+ height: 16px;
22
+ opacity: 0.3;
23
+ background-image: url(../../images/icons/draggable-block-menu.svg);
24
+ }
25
25
  }
26
26
 
27
- .draggable-block-target-line {
27
+ .c-rte-draggable-block-target-line {
28
28
  pointer-events: none;
29
29
  background: deepskyblue;
30
30
  height: 4px;