@crystallize/design-system 1.12.0 → 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 (81) hide show
  1. package/CHANGELOG.md +7 -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 +517 -515
  6. package/dist/index.mjs +398 -396
  7. package/package.json +6 -7
  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/plugins/ActionsPlugin/index.css +3 -0
  29. package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +1 -2
  30. package/src/rich-text-editor/plugins/AutoLinkPlugin/index.tsx +1 -1
  31. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +6 -2
  32. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +10 -6
  33. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.css +32 -17
  34. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx +3 -4
  35. package/src/rich-text-editor/plugins/DimensionsDetectorPlugin/index.tsx +49 -0
  36. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.css +14 -14
  37. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.tsx +4 -4
  38. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.css +87 -21
  39. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx +11 -17
  40. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.css +10 -2
  41. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +17 -17
  42. package/src/rich-text-editor/plugins/LinkPlugin/index.tsx +1 -1
  43. package/src/rich-text-editor/plugins/ListMaxIndentLevelPlugin/index.ts +10 -21
  44. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.css +6 -0
  45. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +2 -2
  46. package/src/rich-text-editor/plugins/ToolbarPlugin/index.css +115 -0
  47. package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +57 -78
  48. package/src/rich-text-editor/plugins/ToolbarPlugin/insert-table.tsx +5 -5
  49. package/src/rich-text-editor/rich-text-editor-icons.css +213 -0
  50. package/src/rich-text-editor/rich-text-editor.css +33 -913
  51. package/src/rich-text-editor/rich-text-editor.stories.tsx +11 -0
  52. package/src/rich-text-editor/rich-text-editor.tsx +13 -27
  53. package/src/rich-text-editor/themes/CrystallizeRTEditorTheme.ts +1 -1
  54. package/src/rich-text-editor/ui/LinkPreview.tsx +7 -8
  55. package/src/rich-text-editor/utils/getSelectedNode.ts +4 -5
  56. package/src/rich-text-editor/utils/point.ts +4 -7
  57. package/src/rich-text-editor/utils/rect.ts +18 -41
  58. package/src/rich-text-editor/utils/url.ts +1 -2
  59. package/src/select/select-root.tsx +1 -1
  60. package/src/select/select.stories.tsx +1 -1
  61. package/src/select/select.ts +0 -1
  62. package/src/slider/Slider.stories.tsx +2 -1
  63. package/src/slider/slider.tsx +2 -2
  64. package/src/spinner/Spinner.stories.tsx +1 -0
  65. package/src/spinner/index.tsx +1 -1
  66. package/src/tag/Tag.stories.tsx +1 -0
  67. package/dist/camera-CR7D2PNH.svg +0 -1
  68. package/dist/clipboard-OSEFDF25.svg +0 -1
  69. package/dist/gear-ICMT4NTP.svg +0 -1
  70. package/dist/journal-code-XUT44HDV.svg +0 -1
  71. package/dist/lock-WCYOZOHW.svg +0 -1
  72. package/dist/lock-fill-JZSKOSHK.svg +0 -1
  73. package/dist/pencil-fill-STFSC26F.svg +0 -1
  74. package/dist/plug-HGGGEVS3.svg +0 -1
  75. package/dist/plug-fill-OTG3U4TN.svg +0 -1
  76. package/src/rich-text-editor/hooks/useReport.ts +0 -64
  77. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.css +0 -14
  78. package/src/rich-text-editor/ui/LinkPreview.css +0 -57
  79. package/src/rich-text-editor/utils/isMobileWidth.ts +0 -7
  80. package/src/rich-text-editor/utils/joinClasses.ts +0 -13
  81. package/src/rich-text-editor/utils/swipe.ts +0 -127
@@ -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 { Dispatch, useCallback, useEffect, useRef, useState } from 'react';
10
10
  import * as React from 'react';
11
11
  import {
@@ -185,10 +185,10 @@ function FloatingLinkEditor({
185
185
  }, [isEditMode]);
186
186
 
187
187
  return (
188
- <div ref={editorRef} className="link-editor">
188
+ <div ref={editorRef} className="c-rte-link-editor">
189
189
  {isEditMode ? (
190
190
  <div>
191
- <div className="border-0 border-b border-gray-100-800 border-solid px-3">
191
+ <div className="c-rte-link-editor-input-group">
192
192
  <InputWithLabel
193
193
  label={tr('linkEditorLink')}
194
194
  type="text"
@@ -197,7 +197,7 @@ function FloatingLinkEditor({
197
197
  />
198
198
  </div>
199
199
 
200
- <div className="border-0 border-b border-gray-100-800 border-solid px-3">
200
+ <div className="c-rte-link-editor-input-group">
201
201
  <InputWithLabel
202
202
  label={tr('linkEditorRel')}
203
203
  type="text"
@@ -205,7 +205,7 @@ function FloatingLinkEditor({
205
205
  onChange={e => setRel(e.target.value)}
206
206
  />
207
207
  </div>
208
- <div className="border-0 border-b border-gray-100-800 border-solid px-3">
208
+ <div className="c-rte-link-editor-input-group">
209
209
  <InputWithLabel
210
210
  label={tr('linkEditorTarget')}
211
211
  type="text"
@@ -213,7 +213,7 @@ function FloatingLinkEditor({
213
213
  onChange={e => setTarget(e.target.value)}
214
214
  />
215
215
  </div>
216
- <div className="flex px-6 py-2 justify-end">
216
+ <div className="c-rte-link-editor-button-wrap">
217
217
  <Button
218
218
  onClick={() => {
219
219
  if (lastSelection !== null) {
@@ -234,21 +234,15 @@ function FloatingLinkEditor({
234
234
  </div>
235
235
  ) : (
236
236
  <>
237
- <div className="link-input !flex flex-nowrap justify-between items-center max-w-full ">
238
- <div className="grid">
237
+ <div className="c-rte-link-editor-link-input">
238
+ <div className="c-rte-link-editor-link-preview">
239
239
  <a href={linkUrl} target="_blank" rel="noopener noreferrer">
240
240
  {linkUrl}
241
241
  </a>
242
242
  {rel || target ? (
243
- <div className="flex mt-1 gap-1">
244
- {rel && (
245
- <div className="text-[10px] text-gray-600-300 px-1 bg-purple-50-900 rounded-md py-0.5">{rel}</div>
246
- )}
247
- {target && (
248
- <div className="text-[10px] text-gray-600-300 px-1 bg-purple-50-900 rounded-md py-0.5">
249
- {target}
250
- </div>
251
- )}
243
+ <div className="c-rte-link-editor-preview-attrs">
244
+ {rel && <div className="c-rte-link-editor-preview-attr">{rel}</div>}
245
+ {target && <div className="c-rte-link-editor-preview-attr">{target}</div>}
252
246
  </div>
253
247
  ) : null}
254
248
  </div>
@@ -1,11 +1,19 @@
1
- .c-floating-text-format-popup {
1
+ .c-rte-floating-text-format-tb-plugin {
2
2
  vertical-align: middle;
3
3
  background-color: #fff;
4
4
  transition: opacity 0.5s;
5
5
  height: 43px;
6
6
  will-change: transform;
7
7
  box-sizing: border-box;
8
- @apply absolute left-0 top-0 z-10 flex rounded-md bg-elevate p-1 opacity-0 shadow-md;
8
+ @apply absolute left-0 top-0 z-10 flex gap-0.5 rounded-md bg-elevate p-1 opacity-0 shadow-md;
9
+
10
+ &__format-icon {
11
+ @apply h-full w-full bg-[length:18px_18px] bg-center bg-no-repeat opacity-60;
12
+
13
+ &.selected {
14
+ @apply bg-purple-50-900 opacity-100;
15
+ }
16
+ }
9
17
  }
10
18
 
11
19
  .c-floating-text-format-popup button.popup-item {
@@ -134,7 +134,7 @@ function TextFormatFloatingToolbar({
134
134
  }, [editor, updateTextFormatFloatingToolbar]);
135
135
 
136
136
  return (
137
- <div ref={popupCharStylesEditorRef} className="c-floating-text-format-popup gap-0.5">
137
+ <div ref={popupCharStylesEditorRef} className="c-rte-floating-text-format-tb-plugin">
138
138
  {editor.isEditable() && (
139
139
  <>
140
140
  <IconButton
@@ -146,8 +146,8 @@ function TextFormatFloatingToolbar({
146
146
  aria-label={tr('actionFormatAsStrongLabel')}
147
147
  >
148
148
  <i
149
- className={`format bold w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
150
- isBold ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
149
+ className={`c-rte-icon-bold c-rte-floating-text-format-tb-plugin__format-icon ${
150
+ isBold ? 'selected' : ''
151
151
  }`}
152
152
  />
153
153
  </IconButton>
@@ -160,8 +160,8 @@ function TextFormatFloatingToolbar({
160
160
  aria-label={tr('actionFormatAsEmphasizedLabel')}
161
161
  >
162
162
  <i
163
- className={`format italic w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
164
- isItalic ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
163
+ className={`c-rte-icon-italic c-rte-floating-text-format-tb-plugin__format-icon ${
164
+ isItalic ? 'selected' : ''
165
165
  }`}
166
166
  />
167
167
  </IconButton>
@@ -174,8 +174,8 @@ function TextFormatFloatingToolbar({
174
174
  aria-label={tr('actionFormatAsUnderlinedLabel')}
175
175
  >
176
176
  <i
177
- className={`format underline w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
178
- isUnderline ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
177
+ className={`c-rte-icon-underline c-rte-floating-text-format-tb-plugin__format-icon ${
178
+ isUnderline ? 'selected' : ''
179
179
  }`}
180
180
  />
181
181
  </IconButton>
@@ -188,8 +188,8 @@ function TextFormatFloatingToolbar({
188
188
  aria-label={tr('actionFormatWithStrikethroughLabel')}
189
189
  >
190
190
  <i
191
- className={`format strikethrough w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
192
- isStrikethrough ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
191
+ className={`c-rte-icon-strikethrough c-rte-floating-text-format-tb-plugin__format-icon ${
192
+ isStrikethrough ? 'selected' : ''
193
193
  }`}
194
194
  />
195
195
  </IconButton>
@@ -202,8 +202,8 @@ function TextFormatFloatingToolbar({
202
202
  aria-label={tr('actionFormatWithSubscriptLabel')}
203
203
  >
204
204
  <i
205
- className={`format subscript w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
206
- isSubscript ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
205
+ className={`c-rte-icon-subscript c-rte-floating-text-format-tb-plugin__format-icon ${
206
+ isSubscript ? 'selected' : ''
207
207
  }`}
208
208
  />
209
209
  </IconButton>
@@ -216,8 +216,8 @@ function TextFormatFloatingToolbar({
216
216
  aria-label={tr('actionFormatWithSuperscriptLabel')}
217
217
  >
218
218
  <i
219
- className={`format superscript w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
220
- isSuperscript ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
219
+ className={`c-rte-icon-superscript c-rte-floating-text-format-tb-plugin__format-icon ${
220
+ isSuperscript ? 'selected' : ''
221
221
  }`}
222
222
  />
223
223
  </IconButton>
@@ -229,8 +229,8 @@ function TextFormatFloatingToolbar({
229
229
  aria-label={tr('actionInsertCodeBlock')}
230
230
  >
231
231
  <i
232
- className={`format code w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
233
- isCode ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
232
+ className={`c-rte-icon-code c-rte-floating-text-format-tb-plugin__format-icon ${
233
+ isCode ? 'selected' : ''
234
234
  }`}
235
235
  />
236
236
  </IconButton>
@@ -240,8 +240,8 @@ function TextFormatFloatingToolbar({
240
240
  aria-label={tr('actionInsertlink')}
241
241
  >
242
242
  <i
243
- className={`format link w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${
244
- isLink ? 'bg-purple-50-900 opacity-100' : 'opacity-60'
243
+ className={`c-rte-icon-link c-rte-floating-text-format-tb-plugin__format-icon ${
244
+ isLink ? 'selected' : ''
245
245
  }`}
246
246
  />
247
247
  </IconButton>
@@ -6,8 +6,8 @@
6
6
  *
7
7
  */
8
8
 
9
- import { LinkPlugin as LexicalLinkPlugin } from '@lexical/react/LexicalLinkPlugin';
10
9
  import * as React from 'react';
10
+ import { LinkPlugin as LexicalLinkPlugin } from '@lexical/react/LexicalLinkPlugin';
11
11
 
12
12
  import { validateUrl } from '../../utils/url';
13
13
 
@@ -6,10 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import type {RangeSelection} from 'lexical';
10
-
11
- import {$getListDepth, $isListItemNode, $isListNode} from '@lexical/list';
12
- import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
9
+ import { useEffect } from 'react';
13
10
  import {
14
11
  $getSelection,
15
12
  $isElementNode,
@@ -17,28 +14,23 @@ import {
17
14
  COMMAND_PRIORITY_CRITICAL,
18
15
  ElementNode,
19
16
  INDENT_CONTENT_COMMAND,
17
+ type RangeSelection,
20
18
  } from 'lexical';
21
- import {useEffect} from 'react';
19
+ import { $getListDepth, $isListItemNode, $isListNode } from '@lexical/list';
20
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
22
21
 
23
22
  type Props = Readonly<{
24
23
  maxDepth: number | null | undefined;
25
24
  }>;
26
25
 
27
- function getElementNodesInSelection(
28
- selection: RangeSelection,
29
- ): Set<ElementNode> {
26
+ function getElementNodesInSelection(selection: RangeSelection): Set<ElementNode> {
30
27
  const nodesInSelection = selection.getNodes();
31
28
 
32
29
  if (nodesInSelection.length === 0) {
33
- return new Set([
34
- selection.anchor.getNode().getParentOrThrow(),
35
- selection.focus.getNode().getParentOrThrow(),
36
- ]);
30
+ return new Set([selection.anchor.getNode().getParentOrThrow(), selection.focus.getNode().getParentOrThrow()]);
37
31
  }
38
32
 
39
- return new Set(
40
- nodesInSelection.map((n) => ($isElementNode(n) ? n : n.getParentOrThrow())),
41
- );
33
+ return new Set(nodesInSelection.map(n => ($isElementNode(n) ? n : n.getParentOrThrow())));
42
34
  }
43
35
 
44
36
  function isIndentPermitted(maxDepth: number): boolean {
@@ -48,8 +40,7 @@ function isIndentPermitted(maxDepth: number): boolean {
48
40
  return false;
49
41
  }
50
42
 
51
- const elementNodesInSelection: Set<ElementNode> =
52
- getElementNodesInSelection(selection);
43
+ const elementNodesInSelection: Set<ElementNode> = getElementNodesInSelection(selection);
53
44
 
54
45
  let totalDepth = 0;
55
46
 
@@ -60,9 +51,7 @@ function isIndentPermitted(maxDepth: number): boolean {
60
51
  const parent = elementNode.getParent();
61
52
 
62
53
  if (!$isListNode(parent)) {
63
- throw new Error(
64
- 'ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent.',
65
- );
54
+ throw new Error('ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent.');
66
55
  }
67
56
 
68
57
  totalDepth = Math.max($getListDepth(parent) + 1, totalDepth);
@@ -72,7 +61,7 @@ function isIndentPermitted(maxDepth: number): boolean {
72
61
  return totalDepth <= maxDepth;
73
62
  }
74
63
 
75
- export default function ListMaxIndentLevelPlugin({maxDepth}: Props): null {
64
+ export default function ListMaxIndentLevelPlugin({ maxDepth }: Props): null {
76
65
  const [editor] = useLexicalComposerContext();
77
66
 
78
67
  useEffect(() => {
@@ -0,0 +1,6 @@
1
+ .c-rte-table-cell-action-button-container {
2
+ position: absolute;
3
+ top: 0;
4
+ left: 0;
5
+ will-change: transform;
6
+ }
@@ -396,13 +396,13 @@ function TableCellActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement
396
396
  }, [menuButtonRef, tableCellNode, editor, anchorElem]);
397
397
 
398
398
  return (
399
- <div className="table-cell-action-button-container" ref={menuButtonRef}>
399
+ <div className="c-rte-table-cell-action-button-container" ref={menuButtonRef}>
400
400
  {tableCellNode != null && (
401
401
  <DropdownMenu.Root
402
402
  onOpenChange={isOpen => setIsMenuOpen(isOpen)}
403
403
  content={<TableActionMenu tableCellNode={tableCellNode} tableStats={tableStats} />}
404
404
  >
405
- <IconButton size="xs" className="table-cell-action-button" aria-label={tr('actionTableOpenOptions')}>
405
+ <IconButton size="xs" aria-label={tr('actionTableOpenOptions')}>
406
406
  <Icon.Arrow />
407
407
  </IconButton>
408
408
  </DropdownMenu.Root>
@@ -0,0 +1,115 @@
1
+ .c-rte-toolbar {
2
+ @apply flex h-12 w-full justify-between overflow-auto rounded-tl-md rounded-tr-md py-1 pl-4 pr-2 align-middle;
3
+
4
+ &__inner {
5
+ @apply flex;
6
+ }
7
+
8
+ &__icon {
9
+ @apply h-6 w-4 border bg-[length:17px_17px] bg-center bg-no-repeat;
10
+
11
+ &.disabled {
12
+ @apply opacity-30;
13
+ }
14
+ }
15
+
16
+ &__block-format__icon {
17
+ @apply h-6 w-6 rounded-md border bg-[length:18px_18px] bg-center bg-no-repeat opacity-60;
18
+
19
+ &.selected {
20
+ @apply bg-purple-50-900 opacity-100;
21
+ }
22
+ }
23
+
24
+ &__block-format__text {
25
+ @apply min-w-[150px] px-3 text-sm font-normal;
26
+
27
+ &.selected {
28
+ @apply font-bold;
29
+ }
30
+ }
31
+
32
+ &__toggle-icon {
33
+ @apply h-6 w-6 border bg-[length:18px_18px] bg-center bg-no-repeat;
34
+ }
35
+
36
+ &__code-lang {
37
+ &__button-text {
38
+ @apply text-sm font-medium;
39
+ }
40
+ &__sel-item {
41
+ @apply block min-w-[200px] px-3 text-sm font-normal opacity-80;
42
+
43
+ &.selected {
44
+ @apply font-bold opacity-100;
45
+ }
46
+ }
47
+ }
48
+
49
+ &__divider {
50
+ width: 1px;
51
+ background-color: #eee;
52
+ margin: 0 4px;
53
+ }
54
+
55
+ &__actions-rest {
56
+ @apply flex gap-1;
57
+ }
58
+
59
+ &__icon-btn {
60
+ @apply opacity-60;
61
+
62
+ &.selected {
63
+ @apply !bg-purple-50-900 opacity-100;
64
+ }
65
+
66
+ &__icon {
67
+ @apply h-full w-full border bg-[length:18px_18px] bg-center bg-no-repeat;
68
+ }
69
+ }
70
+
71
+ &__dd-item {
72
+ &__icon {
73
+ @apply h-6 w-6 rounded-sm border bg-[length:16px_16px] bg-center bg-no-repeat opacity-60;
74
+
75
+ &.selected {
76
+ @apply !bg-purple-50-900 opacity-100;
77
+ }
78
+ }
79
+ &__text {
80
+ @apply px-3 font-sans text-sm font-normal;
81
+
82
+ &.selected {
83
+ @apply font-medium;
84
+ }
85
+
86
+ &--clear {
87
+ @apply ml-3 text-pink-600-300;
88
+ }
89
+ }
90
+
91
+ &--table {
92
+ @apply flex items-center font-sans font-normal;
93
+ }
94
+ }
95
+
96
+ &__plus {
97
+ @apply h-full w-full border bg-[length:20px_20px] bg-center bg-no-repeat;
98
+ }
99
+ }
100
+
101
+ .c-rte-insert-table {
102
+ @apply items-center justify-between;
103
+
104
+ &__dimensions {
105
+ @apply grid grid-cols-[1fr_1px_1fr] rounded-md border border-solid border-gray-100-800 shadow-sm;
106
+
107
+ &__separator {
108
+ @apply h-full bg-gray-100-800;
109
+ }
110
+ }
111
+
112
+ &__actions {
113
+ @apply mt-3 flex justify-end;
114
+ }
115
+ }