@vonaffenfels/slate-editor 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonaffenfels/slate-editor",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -71,7 +71,7 @@
71
71
  "cssnano": "^5.0.1",
72
72
  "escape-html": "^1.0.3"
73
73
  },
74
- "gitHead": "1ad8ddd858ff27ea19e568d79f189f20a2ef0488",
74
+ "gitHead": "2dc1a5a219755f4b1036840f4c1bc9356749eb28",
75
75
  "publishConfig": {
76
76
  "access": "public"
77
77
  }
package/scss/editor.scss CHANGED
@@ -390,7 +390,7 @@
390
390
  }
391
391
  }
392
392
 
393
- button {
393
+ .button {
394
394
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
395
395
  width: 100%;
396
396
  padding: 8px 0.75rem !important;
@@ -402,15 +402,15 @@ button {
402
402
  border-radius: 4px !important;
403
403
  }
404
404
 
405
- button:hover {
405
+ .button:hover {
406
406
  background-color: #0275F0 !important;
407
407
  }
408
408
 
409
- button:active {
409
+ .button:active {
410
410
  background-color: #0262C9 !important;
411
411
  }
412
412
 
413
- button.button--secondary {
413
+ .button.button--secondary {
414
414
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
415
415
  width: 100%;
416
416
  padding: 8px 0.75rem !important;
@@ -422,12 +422,12 @@ button.button--secondary {
422
422
  border-radius: 4px !important;
423
423
  }
424
424
 
425
- button.button--secondary:hover {
425
+ .button.button--secondary:hover {
426
426
  background-color: #036fe3 !important;
427
427
  color: #FFFFFF !important;
428
428
  }
429
429
 
430
- button.button--secondary:active {
430
+ .button.button--secondary:active {
431
431
  background-color: #0262C9 !important;
432
432
  color: #FFFFFF !important;
433
433
  }
@@ -67,14 +67,14 @@ export default function BlockEditor({
67
67
  ];
68
68
 
69
69
  const [loadedStorybookStories, setLoadedStorybookStories] = useState([]);
70
- const [isSidebarLoading, setIsSidebarLoading] = useState(false);
70
+ const [isLoadingStories, setIsLoadingStories] = useState(false);
71
71
 
72
72
  const loadStories = async () => {
73
- setIsSidebarLoading(true);
73
+ setIsLoadingStories(true);
74
74
 
75
75
  let loadedStories = await storybookStories();
76
76
 
77
- setIsSidebarLoading(false);
77
+ setIsLoadingStories(false);
78
78
 
79
79
  setLoadedStorybookStories(loadedStories);
80
80
  };
@@ -252,7 +252,13 @@ export default function BlockEditor({
252
252
  onChange={onSlateChange}
253
253
  >
254
254
  <div>
255
- <Toolbar hover={false} onSaveClick={onSaveClick}/>
255
+ <Toolbar
256
+ hover={false}
257
+ onSaveClick={onSaveClick}
258
+ storybookStories={loadedStorybookStories}
259
+ isLoadingStories={isLoadingStories}
260
+ editor={editor}
261
+ sdk={contentfulSdk}/>
256
262
  </div>
257
263
  <div className="relative h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
258
264
  {isLoading && (
@@ -290,7 +296,7 @@ export default function BlockEditor({
290
296
  storybookElement={selectedStorybookElement}
291
297
  onChange={handleSidebarEditorChange}
292
298
  storybookStories={loadedStorybookStories}
293
- isLoading={isSidebarLoading}
299
+ isLoading={isLoadingStories}
294
300
  onClose={handleSidebarClose}
295
301
  onDelete={handleSidebarDeleteClick}
296
302
  onMove={handleSidebarMoveClick}
@@ -26,7 +26,7 @@ export const AssetList = ({
26
26
  onChange={handleChange}
27
27
  />
28
28
  <hr className="my-2" style={{borderColor: "#cfd9e0"}}/>
29
- {onAddClick && index === assets.length - 1 && <button onClick={onAddClick} className="button--secondary">Hinzufügen</button>}
29
+ {onAddClick && index === assets.length - 1 && <button onClick={onAddClick} className="button button--secondary">Hinzufügen</button>}
30
30
  </>
31
31
  ));
32
32
 
@@ -243,6 +243,7 @@ export const SidebarEditorField = ({
243
243
  <>
244
244
  {!!value && <div className="mb-2"><Asset sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} onChange={v => onChange(fieldKey, v)} /></div>}
245
245
  <button
246
+ className="button"
246
247
  onClick={() => {
247
248
  sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
248
249
  onChange(fieldKey, content);
@@ -271,6 +272,7 @@ export const SidebarEditorField = ({
271
272
  </details>
272
273
  )}
273
274
  <button
275
+ className="button"
274
276
  onClick={() => {
275
277
  sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
276
278
  onChange(fieldKey, contents);
@@ -284,6 +286,7 @@ export const SidebarEditorField = ({
284
286
  <>
285
287
  {!!value && <div className="mb-2"><Asset cloudinary sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} /></div>}
286
288
  <button
289
+ className="button"
287
290
  onClick={() => {
288
291
  sdk.dialogs.openCurrentApp({
289
292
  width: "fullWidth",
@@ -328,6 +331,7 @@ export const SidebarEditorField = ({
328
331
  </details>
329
332
  )}
330
333
  <button
334
+ className="button"
331
335
  onClick={() => {
332
336
  sdk.dialogs.openCurrentApp({
333
337
  width: "fullWidth",
@@ -384,7 +388,7 @@ export const SidebarEditorField = ({
384
388
  </div>
385
389
  );
386
390
  })}
387
- <button className="button--secondary" onClick={() => onChange(fieldKey, [...(storybookElement.attributes[fieldKey] || []), {}])}>Neue Zeile</button>
391
+ <button className="button button--secondary" onClick={() => onChange(fieldKey, [...(storybookElement.attributes[fieldKey] || []), {}])}>Neue Zeile</button>
388
392
  </div>
389
393
  </details>
390
394
  );
@@ -21,6 +21,12 @@ import {StorybookButton} from "./Element";
21
21
  import {LinkButton} from "./Link";
22
22
  import {InsertDividerButton} from "./Insert";
23
23
  import {InsertGridButton} from "./Layout";
24
+ import {
25
+ Autocomplete, Spinner,
26
+ } from "@contentful/forma-36-react-components";
27
+ import {Transforms} from "slate";
28
+
29
+ const devMode = localStorage.getItem("dev-mode") === "true";
24
30
 
25
31
  export const Portal = ({children}) => {
26
32
  return ReactDOM.createPortal(children, window.document.body);
@@ -29,9 +35,12 @@ export const Portal = ({children}) => {
29
35
  export const Toolbar = ({
30
36
  hover,
31
37
  onSaveClick,
38
+ storybookStories,
39
+ isLoadingStories,
40
+ editor,
41
+ sdk,
32
42
  }) => {
33
43
  const ref = useRef();
34
- const editor = useSlate();
35
44
 
36
45
  useEffect(() => {
37
46
  if (!hover) {
@@ -93,39 +102,50 @@ export const Toolbar = ({
93
102
  })}
94
103
  >
95
104
  <div className="toolbar-btns">
96
- <div className="flex grow">
97
- <FormatButtonBold/>
98
- <FormatButtonItalic/>
99
- <FormatButtonUnderline/>
100
- <FormatButtonStrikethrough/>
101
-
102
- <LinkButton/>
103
-
104
- <ToobarHoverExpandButton>
105
- <BlockButtonHeading level={2}/>
106
- <BlockButtonHeading level={3}/>
107
- <BlockButtonHeading level={4}/>
108
- </ToobarHoverExpandButton>
109
-
110
- <ToobarHoverExpandButton>
111
- <BlockButtonUnorderedList/>
112
- <BlockButtonOrderedList/>
113
- <BlockButtonArrowList/>
114
- </ToobarHoverExpandButton>
115
-
116
- <BlockButtonBlockquote/>
117
-
118
- <ToobarHoverExpandButton>
119
- <AlignButtonLeft/>
120
- <AlignButtonCenter/>
121
- <AlignButtonRight/>
122
- </ToobarHoverExpandButton>
123
-
124
- <ToobarHoverExpandButton>
125
- <StorybookButton/>
126
- <InsertDividerButton/>
127
- <InsertGridButton/>
128
- </ToobarHoverExpandButton>
105
+ <div className="flex grow items-center">
106
+ <div className="flex">
107
+ <FormatButtonBold/>
108
+ <FormatButtonItalic/>
109
+ <FormatButtonUnderline/>
110
+ <FormatButtonStrikethrough/>
111
+
112
+ <LinkButton/>
113
+
114
+ <ToobarHoverExpandButton>
115
+ <BlockButtonHeading level={2}/>
116
+ <BlockButtonHeading level={3}/>
117
+ <BlockButtonHeading level={4}/>
118
+ </ToobarHoverExpandButton>
119
+
120
+ <ToobarHoverExpandButton>
121
+ <BlockButtonUnorderedList/>
122
+ <BlockButtonOrderedList/>
123
+ <BlockButtonArrowList/>
124
+ </ToobarHoverExpandButton>
125
+
126
+ <BlockButtonBlockquote/>
127
+
128
+ <ToobarHoverExpandButton>
129
+ <AlignButtonLeft/>
130
+ <AlignButtonCenter/>
131
+ <AlignButtonRight/>
132
+ </ToobarHoverExpandButton>
133
+
134
+ <ToobarHoverExpandButton>
135
+ <StorybookButton/>
136
+ <InsertDividerButton/>
137
+ <InsertGridButton/>
138
+ </ToobarHoverExpandButton>
139
+ </div>
140
+
141
+ <div>
142
+ <ElementAutocomplete
143
+ isLoading={isLoadingStories}
144
+ storybookStories={storybookStories}
145
+ editor={editor}
146
+ storyContext={sdk.parameters.instance.storyContext}
147
+ />
148
+ </div>
129
149
  </div>
130
150
  {!!onSaveClick && <button className="!w-auto !border-0 !bg-green-600 !text-xs font-bold text-white hover:!bg-green-700" onClick={onSaveClick}>Änderungen speichern</button>}
131
151
  </div>
@@ -143,6 +163,84 @@ export const Toolbar = ({
143
163
  }
144
164
  };
145
165
 
166
+ const ElementAutocomplete = ({
167
+ storybookStories,
168
+ isLoading,
169
+ editor,
170
+ storyContext,
171
+ }) => {
172
+ const [filteredItems, setFilteredItems] = React.useState(items);
173
+
174
+ const items = (storybookStories || []).map(story => {
175
+ let storyTitleSplit = story.title.split("/");
176
+
177
+ if (!story.id) {
178
+ return;
179
+ }
180
+
181
+ let splitStoryContext = storyContext.split(",");
182
+ let isItemInContext = splitStoryContext.find(context => {
183
+ return Array.isArray(story.storyContext) ? story.storyContext.includes(context) : context === story.storyContext;
184
+ });
185
+
186
+ if (!devMode && !isItemInContext) {
187
+ return;
188
+ }
189
+
190
+ return {
191
+ value: story.id.toLowerCase(),
192
+ label: storyTitleSplit[storyTitleSplit.length - 1],
193
+ stories: story.stories,
194
+ };
195
+ }).filter(Boolean);
196
+
197
+ useEffect(() => {
198
+ setFilteredItems(items);
199
+ }, [storybookStories]);
200
+
201
+ const handleQueryChange = (query) => {
202
+ setFilteredItems(query ? items.filter((item) => item.label.toLowerCase().includes(query.toLowerCase())) : items);
203
+ };
204
+
205
+ const handleOnChange = (item) => {
206
+ let element = {
207
+ children: [{text: ''}],
208
+ type: "storybook",
209
+ block: item.value,
210
+ attributes: {...(item?.stories?.[0]?.args || item?.stories?.[1]?.args || {})},
211
+ };
212
+
213
+ Transforms.insertNodes(editor, [element]);
214
+ };
215
+
216
+ useEffect(() => {
217
+ let autoCompleteElement = document.getElementsByClassName("element-autocomplete")[0];
218
+
219
+ if (autoCompleteElement) {
220
+ autoCompleteElement.value = "";
221
+ }
222
+ }, []);
223
+
224
+ return (
225
+ <Autocomplete
226
+ items={filteredItems}
227
+ onQueryChange={handleQueryChange}
228
+ isLoading={isLoading}
229
+ placeholder={'Suchen...'}
230
+ emptyListMessage={'Keine Komponenten gefunden'}
231
+ noMatchesMessage={'Keine Ergebnisse gefunden'}
232
+ dropdownProps={{isFullWidth: true}}
233
+ maxHeight={300}
234
+ onChange={handleOnChange}
235
+ width="medium"
236
+ >
237
+ {(options) =>
238
+ options.map((option) => <span key={option.value}>{option.label}</span>)
239
+ }
240
+ </Autocomplete>
241
+ );
242
+ };
243
+
146
244
  export const ToobarHoverExpandButton = ({children}) => {
147
245
  return <span
148
246
  className={