@uipath/apollo-react 4.62.1 → 4.64.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 (25) hide show
  1. package/dist/canvas/components/StickyNoteNode/StickyNoteMedia.cjs +449 -0
  2. package/dist/canvas/components/StickyNoteNode/StickyNoteMedia.d.ts +45 -0
  3. package/dist/canvas/components/StickyNoteNode/StickyNoteMedia.d.ts.map +1 -0
  4. package/dist/canvas/components/StickyNoteNode/StickyNoteMedia.js +394 -0
  5. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaDialog.cjs +379 -0
  6. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaDialog.d.ts +8 -0
  7. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaDialog.d.ts.map +1 -0
  8. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaDialog.js +345 -0
  9. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaMarkdown.cjs +272 -0
  10. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaMarkdown.d.ts +18 -0
  11. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaMarkdown.d.ts.map +1 -0
  12. package/dist/canvas/components/StickyNoteNode/StickyNoteMediaMarkdown.js +235 -0
  13. package/dist/canvas/components/StickyNoteNode/StickyNoteNode.cjs +130 -17
  14. package/dist/canvas/components/StickyNoteNode/StickyNoteNode.d.ts +2 -1
  15. package/dist/canvas/components/StickyNoteNode/StickyNoteNode.d.ts.map +1 -1
  16. package/dist/canvas/components/StickyNoteNode/StickyNoteNode.js +130 -17
  17. package/dist/canvas/locales/en.cjs +1 -1
  18. package/dist/canvas/locales/en.d.ts.map +1 -1
  19. package/dist/canvas/locales/en.js +1 -1
  20. package/dist/canvas/storybook-utils/manifests/node-definitions.d.ts.map +1 -1
  21. package/dist/canvas/styles/tailwind.canvas.css +1 -1
  22. package/dist/canvas/utils/icon-registry.cjs +4 -0
  23. package/dist/canvas/utils/icon-registry.d.ts.map +1 -1
  24. package/dist/canvas/utils/icon-registry.js +5 -1
  25. package/package.json +1 -1
@@ -0,0 +1,235 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { CanvasIcon } from "../../index.js";
3
+ import { createContext, createElement, useContext, useState } from "react";
4
+ import { useSafeLingui } from "../../../i18n/index.js";
5
+ import { parseStickyNoteMediaMarker, parseStickyNoteMediaSource } from "./StickyNoteMedia.js";
6
+ const StickyNoteMediaMarkdownContext = /*#__PURE__*/ createContext({
7
+ editable: false
8
+ });
9
+ function StickyNoteMediaMarkdownProvider({ value, children }) {
10
+ return /*#__PURE__*/ jsx(StickyNoteMediaMarkdownContext.Provider, {
11
+ value: value,
12
+ children: children
13
+ });
14
+ }
15
+ function sourceRange(node) {
16
+ const start = node?.position?.start?.offset;
17
+ const end = node?.position?.end?.offset;
18
+ return 'number' == typeof start && 'number' == typeof end ? {
19
+ start,
20
+ end
21
+ } : null;
22
+ }
23
+ function MediaContainer({ fullWidth, children }) {
24
+ return /*#__PURE__*/ jsx("span", {
25
+ className: "relative my-2 block max-w-full overflow-hidden rounded-md",
26
+ style: {
27
+ width: fullWidth ? '100%' : 'min(320px, 100%)'
28
+ },
29
+ "data-sticky-media": true,
30
+ "data-sticky-full-width": fullWidth,
31
+ children: children
32
+ });
33
+ }
34
+ function MediaEditButton({ onClick }) {
35
+ const { _ } = useSafeLingui();
36
+ const label = _({
37
+ id: 'sticky-note.media.edit',
38
+ message: 'Edit media'
39
+ });
40
+ return /*#__PURE__*/ jsx("button", {
41
+ type: "button",
42
+ "data-sticky-media-control": true,
43
+ "aria-label": label,
44
+ title: label,
45
+ className: "absolute right-1 top-1 z-10 inline-flex h-7 w-7 items-center justify-center rounded bg-surface-raised/95 text-foreground opacity-80 shadow-sm transition-opacity hover:bg-surface-hover hover:opacity-100 focus-visible:opacity-100",
46
+ onClick: (event)=>{
47
+ event.preventDefault();
48
+ event.stopPropagation();
49
+ onClick();
50
+ },
51
+ onDoubleClick: (event)=>event.stopPropagation(),
52
+ onPointerDown: (event)=>event.stopPropagation(),
53
+ children: /*#__PURE__*/ jsx(CanvasIcon, {
54
+ icon: "pencil",
55
+ size: 14
56
+ })
57
+ });
58
+ }
59
+ function StickyNoteMediaImage({ src, alt = '', title, node, fallbackImage, ...imageProps }) {
60
+ const { _ } = useSafeLingui();
61
+ const { editable, onEditMedia } = useContext(StickyNoteMediaMarkdownContext);
62
+ const [failedImageUrl, setFailedImageUrl] = useState(null);
63
+ const [loadedYouTubeId, setLoadedYouTubeId] = useState(null);
64
+ const mediaMarker = parseStickyNoteMediaMarker(title);
65
+ const media = 'string' == typeof src ? parseStickyNoteMediaSource(src, alt, title) : null;
66
+ const range = sourceRange(node);
67
+ if (!media) {
68
+ if (mediaMarker) {
69
+ const unavailableLabel = _({
70
+ id: 'sticky-note.media.unavailable',
71
+ message: 'Media unavailable'
72
+ });
73
+ return /*#__PURE__*/ jsx(MediaContainer, {
74
+ fullWidth: mediaMarker.fullWidth,
75
+ children: /*#__PURE__*/ jsx("span", {
76
+ role: "img",
77
+ "aria-label": alt || unavailableLabel,
78
+ className: "flex min-h-20 items-center justify-center bg-black/10 px-3 text-center text-xs text-foreground-muted",
79
+ children: unavailableLabel
80
+ })
81
+ });
82
+ }
83
+ if (fallbackImage) {
84
+ const fallbackProps = {
85
+ ...imageProps,
86
+ src,
87
+ alt,
88
+ title
89
+ };
90
+ return 'string' == typeof fallbackImage ? /*#__PURE__*/ createElement(fallbackImage, fallbackProps) : /*#__PURE__*/ createElement(fallbackImage, {
91
+ ...fallbackProps,
92
+ node
93
+ });
94
+ }
95
+ return /*#__PURE__*/ jsx("img", {
96
+ ...imageProps,
97
+ src: src,
98
+ alt: alt,
99
+ title: title
100
+ });
101
+ }
102
+ const editButton = editable && range && onEditMedia && /*#__PURE__*/ jsx(MediaEditButton, {
103
+ onClick: ()=>onEditMedia(media, range)
104
+ });
105
+ if ('youtube' === media.kind) {
106
+ const playLabel = _({
107
+ id: 'sticky-note.media.play-video',
108
+ message: 'Play video'
109
+ });
110
+ const youtubeLoaded = loadedYouTubeId === media.videoId;
111
+ return /*#__PURE__*/ jsxs(MediaContainer, {
112
+ fullWidth: media.fullWidth,
113
+ children: [
114
+ youtubeLoaded ? /*#__PURE__*/ jsx("iframe", {
115
+ src: `https://www.youtube-nocookie.com/embed/${media.videoId}?autoplay=1`,
116
+ title: _({
117
+ id: 'sticky-note.media.youtube-title',
118
+ message: 'YouTube video'
119
+ }),
120
+ loading: "lazy",
121
+ referrerPolicy: "strict-origin-when-cross-origin",
122
+ sandbox: "allow-scripts allow-same-origin allow-presentation",
123
+ allow: "autoplay; encrypted-media; fullscreen; picture-in-picture",
124
+ allowFullScreen: true,
125
+ className: "block aspect-video w-full border-0",
126
+ onPointerDown: (event)=>event.stopPropagation()
127
+ }) : /*#__PURE__*/ jsxs("button", {
128
+ type: "button",
129
+ "data-sticky-media-control": true,
130
+ "aria-label": playLabel,
131
+ className: "group relative flex aspect-video w-full items-center justify-center overflow-hidden bg-black text-sm font-medium text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-white",
132
+ onClick: (event)=>{
133
+ event.preventDefault();
134
+ event.stopPropagation();
135
+ setLoadedYouTubeId(media.videoId);
136
+ },
137
+ onDoubleClick: (event)=>event.stopPropagation(),
138
+ onPointerDown: (event)=>event.stopPropagation(),
139
+ children: [
140
+ /*#__PURE__*/ jsx("img", {
141
+ src: `https://i.ytimg.com/vi/${media.videoId}/hqdefault.jpg`,
142
+ alt: "",
143
+ draggable: false,
144
+ loading: "lazy",
145
+ decoding: "async",
146
+ referrerPolicy: "no-referrer",
147
+ className: "absolute inset-0 h-full w-full object-cover opacity-80 transition-opacity group-hover:opacity-70"
148
+ }),
149
+ /*#__PURE__*/ jsxs("span", {
150
+ className: "relative z-10 inline-flex items-center gap-2 rounded-full bg-black/70 px-4 py-2 shadow-sm",
151
+ children: [
152
+ /*#__PURE__*/ jsx(CanvasIcon, {
153
+ icon: "play",
154
+ size: 18
155
+ }),
156
+ playLabel
157
+ ]
158
+ })
159
+ ]
160
+ }),
161
+ editButton
162
+ ]
163
+ });
164
+ }
165
+ if ('publicVideo' === media.kind) {
166
+ const videoLabel = alt || _({
167
+ id: 'sticky-note.media.video-label',
168
+ message: 'Embedded video'
169
+ });
170
+ return /*#__PURE__*/ jsxs(MediaContainer, {
171
+ fullWidth: media.fullWidth,
172
+ children: [
173
+ /*#__PURE__*/ jsx("video", {
174
+ src: media.url,
175
+ "aria-label": videoLabel,
176
+ controls: true,
177
+ preload: "metadata",
178
+ playsInline: true,
179
+ className: "block h-auto w-full bg-black",
180
+ onClick: (event)=>event.stopPropagation(),
181
+ onDoubleClick: (event)=>event.stopPropagation(),
182
+ onPointerDown: (event)=>event.stopPropagation(),
183
+ children: _({
184
+ id: 'sticky-note.media.video-unavailable',
185
+ message: 'Video playback is unavailable.'
186
+ })
187
+ }),
188
+ editButton
189
+ ]
190
+ });
191
+ }
192
+ const imageFailed = failedImageUrl === media.url;
193
+ return /*#__PURE__*/ jsxs(MediaContainer, {
194
+ fullWidth: media.fullWidth,
195
+ children: [
196
+ imageFailed ? /*#__PURE__*/ jsx("span", {
197
+ role: "img",
198
+ "aria-label": alt || _({
199
+ id: 'sticky-note.media.image-unavailable-label',
200
+ message: 'Image unavailable'
201
+ }),
202
+ className: "flex min-h-20 items-center justify-center bg-black/10 px-3 text-center text-xs text-foreground-muted",
203
+ children: _({
204
+ id: 'sticky-note.media.image-unavailable',
205
+ message: 'Image unavailable'
206
+ })
207
+ }) : /*#__PURE__*/ jsx("img", {
208
+ ...imageProps,
209
+ src: media.url,
210
+ alt: alt,
211
+ draggable: false,
212
+ loading: "lazy",
213
+ decoding: "async",
214
+ referrerPolicy: "no-referrer",
215
+ style: {
216
+ display: 'block',
217
+ maxWidth: '100%',
218
+ width: media.fullWidth ? '100%' : 'auto',
219
+ height: 'auto'
220
+ },
221
+ onError: ()=>setFailedImageUrl(media.url)
222
+ }),
223
+ editButton
224
+ ]
225
+ });
226
+ }
227
+ function createStickyNoteMediaMarkdownComponents(fallbackImage) {
228
+ return {
229
+ img: (props)=>/*#__PURE__*/ jsx(StickyNoteMediaImage, {
230
+ ...props,
231
+ fallbackImage: fallbackImage
232
+ })
233
+ };
234
+ }
235
+ export { StickyNoteMediaMarkdownProvider, createStickyNoteMediaMarkdownComponents };
@@ -56,6 +56,9 @@ const external_NodeViewportOverlay_cjs_namespaceObject = require("../NodeViewpor
56
56
  const external_Toolbar_index_cjs_namespaceObject = require("../Toolbar/index.cjs");
57
57
  const external_FormattingToolbar_cjs_namespaceObject = require("./FormattingToolbar.cjs");
58
58
  const external_markdown_formatting_index_cjs_namespaceObject = require("./markdown-formatting/index.cjs");
59
+ const external_StickyNoteMedia_cjs_namespaceObject = require("./StickyNoteMedia.cjs");
60
+ const external_StickyNoteMediaDialog_cjs_namespaceObject = require("./StickyNoteMediaDialog.cjs");
61
+ const external_StickyNoteMediaMarkdown_cjs_namespaceObject = require("./StickyNoteMediaMarkdown.cjs");
59
62
  const external_StickyNoteNode_styles_cjs_namespaceObject = require("./StickyNoteNode.styles.cjs");
60
63
  const external_StickyNoteNode_types_cjs_namespaceObject = require("./StickyNoteNode.types.cjs");
61
64
  const external_StickyNoteNode_utils_cjs_namespaceObject = require("./StickyNoteNode.utils.cjs");
@@ -63,13 +66,14 @@ const external_useMarkdownShortcuts_cjs_namespaceObject = require("./useMarkdown
63
66
  const external_useScrollCapture_cjs_namespaceObject = require("./useScrollCapture.cjs");
64
67
  const minWidth = 8 * external_constants_cjs_namespaceObject.GRID_SPACING;
65
68
  const minHeight = 8 * external_constants_cjs_namespaceObject.GRID_SPACING;
66
- const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = 'Add text', renderPlaceholderOnSelect = false, readOnly = false, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, formattingActions, markdownComponents: customMarkdownComponents })=>{
69
+ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = 'Add text', renderPlaceholderOnSelect = false, readOnly = false, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, enableMediaEmbedding = false, formattingActions, markdownComponents: customMarkdownComponents })=>{
67
70
  const { _ } = (0, index_cjs_namespaceObject.useSafeLingui)();
68
71
  const { updateNodeData, deleteElements } = (0, react_cjs_namespaceObject.useReactFlow)();
69
72
  const { multipleNodesSelected } = (0, SelectionStateContext_cjs_namespaceObject.useSelectionState)();
70
73
  const [isEditing, setIsEditing] = (0, external_react_namespaceObject.useState)(!readOnly && (data.autoFocus ?? false));
71
74
  const [isResizing, setIsResizing] = (0, external_react_namespaceObject.useState)(false);
72
75
  const [isColorPickerOpen, setIsColorPickerOpen] = (0, external_react_namespaceObject.useState)(false);
76
+ const [mediaDialog, setMediaDialog] = (0, external_react_namespaceObject.useState)(null);
73
77
  const [localContent, setLocalContent] = (0, external_react_namespaceObject.useState)(data.content || '');
74
78
  const latestContentRef = (0, external_react_namespaceObject.useRef)(localContent);
75
79
  const textAreaRef = (0, external_react_namespaceObject.useRef)(null);
@@ -244,6 +248,92 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
244
248
  updateLocalContent,
245
249
  updateNodeData
246
250
  ]);
251
+ const openMediaDialog = (0, external_react_namespaceObject.useCallback)((context)=>{
252
+ const { selection } = context;
253
+ setMediaDialog({
254
+ source: 'editor',
255
+ context,
256
+ token: (0, external_StickyNoteMedia_cjs_namespaceObject.findStickyNoteMediaAtSelection)(selection.value, selection.selectionStart, selection.selectionEnd)
257
+ });
258
+ }, []);
259
+ const mediaFormattingAction = (0, external_react_namespaceObject.useMemo)(()=>({
260
+ id: 'sticky-note-embed-media',
261
+ icon: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_index_cjs_namespaceObject.CanvasIcon, {
262
+ icon: "image-plus",
263
+ size: 14
264
+ }),
265
+ label: _({
266
+ id: 'sticky-note.media.embed-action',
267
+ message: 'Embed image or video'
268
+ }),
269
+ onAction: openMediaDialog
270
+ }), [
271
+ _,
272
+ openMediaDialog
273
+ ]);
274
+ const effectiveFormattingActions = (0, external_react_namespaceObject.useMemo)(()=>enableMediaEmbedding ? [
275
+ mediaFormattingAction,
276
+ ...formattingActions ?? []
277
+ ] : formattingActions ?? [], [
278
+ enableMediaEmbedding,
279
+ formattingActions,
280
+ mediaFormattingAction
281
+ ]);
282
+ const handleEditRenderedMedia = (0, external_react_namespaceObject.useCallback)((media, range)=>{
283
+ const sourceContent = latestContentRef.current;
284
+ const renderedTokens = (0, external_StickyNoteMedia_cjs_namespaceObject.parseStickyNoteMediaTokens)((0, external_StickyNoteNode_utils_cjs_namespaceObject.preserveNewlines)(sourceContent));
285
+ const renderedIndex = renderedTokens.findIndex((token)=>token.start === range.start && token.end === range.end);
286
+ const sourceToken = renderedIndex >= 0 ? (0, external_StickyNoteMedia_cjs_namespaceObject.parseStickyNoteMediaTokens)(sourceContent)[renderedIndex] : void 0;
287
+ setMediaDialog({
288
+ source: 'rendered',
289
+ token: sourceToken ?? {
290
+ media,
291
+ ...range
292
+ }
293
+ });
294
+ }, []);
295
+ const cancelMediaDialog = (0, external_react_namespaceObject.useCallback)(()=>{
296
+ const current = mediaDialog;
297
+ setMediaDialog(null);
298
+ if (current?.source === 'editor') current.context.resume();
299
+ }, [
300
+ mediaDialog
301
+ ]);
302
+ (0, external_react_namespaceObject.useEffect)(()=>{
303
+ if (!mediaDialog || enableMediaEmbedding && !readOnly) return;
304
+ setMediaDialog(null);
305
+ skipBlurRef.current = null;
306
+ if (!readOnly && 'editor' === mediaDialog.source) mediaDialog.context.resume();
307
+ }, [
308
+ enableMediaEmbedding,
309
+ mediaDialog,
310
+ readOnly
311
+ ]);
312
+ const submitMediaDialog = (0, external_react_namespaceObject.useCallback)((media)=>{
313
+ if (!mediaDialog) return;
314
+ const block = (0, external_StickyNoteMedia_cjs_namespaceObject.serializeStickyNoteMedia)(media);
315
+ if ('editor' === mediaDialog.source) {
316
+ const currentValue = mediaDialog.context.currentValue();
317
+ const next = mediaDialog.token ? (0, external_StickyNoteMedia_cjs_namespaceObject.replaceStickyNoteMedia)(currentValue, mediaDialog.token, block) ?? (0, external_StickyNoteMedia_cjs_namespaceObject.insertStickyNoteMedia)(currentValue, block, null) : (0, external_StickyNoteMedia_cjs_namespaceObject.insertStickyNoteMedia)(currentValue, block, mediaDialog.context.selection);
318
+ setMediaDialog(null);
319
+ mediaDialog.context.commit(next);
320
+ return;
321
+ }
322
+ const currentValue = latestContentRef.current;
323
+ const next = (0, external_StickyNoteMedia_cjs_namespaceObject.replaceStickyNoteMedia)(currentValue, mediaDialog.token, block) ?? (0, external_StickyNoteMedia_cjs_namespaceObject.insertStickyNoteMedia)(currentValue, block, null);
324
+ setMediaDialog(null);
325
+ updateLocalContent(next.value);
326
+ onContentChange?.(next.value);
327
+ updateNodeData(id, {
328
+ content: next.value
329
+ });
330
+ }, [
331
+ id,
332
+ mediaDialog,
333
+ onContentChange,
334
+ updateLocalContent,
335
+ updateNodeData
336
+ ]);
247
337
  const updateActiveFormats = (0, external_react_namespaceObject.useCallback)(()=>{
248
338
  if (!textAreaRef.current) return;
249
339
  const next = (0, external_markdown_formatting_index_cjs_namespaceObject.detectActiveFormats)({
@@ -372,12 +462,27 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
372
462
  children: children
373
463
  })
374
464
  }), []);
465
+ const mediaMarkdownComponents = (0, external_react_namespaceObject.useMemo)(()=>(0, external_StickyNoteMediaMarkdown_cjs_namespaceObject.createStickyNoteMediaMarkdownComponents)(customMarkdownComponents?.img), [
466
+ customMarkdownComponents?.img
467
+ ]);
375
468
  const markdownComponents = (0, external_react_namespaceObject.useMemo)(()=>({
376
469
  ...customMarkdownComponents,
470
+ ...enableMediaEmbedding ? mediaMarkdownComponents : {},
377
471
  ...builtInMarkdownComponents
378
472
  }), [
379
473
  builtInMarkdownComponents,
380
- customMarkdownComponents
474
+ customMarkdownComponents,
475
+ enableMediaEmbedding,
476
+ mediaMarkdownComponents
477
+ ]);
478
+ const mediaMarkdownOptions = (0, external_react_namespaceObject.useMemo)(()=>({
479
+ editable: enableMediaEmbedding && selected && !readOnly,
480
+ onEditMedia: handleEditRenderedMedia
481
+ }), [
482
+ enableMediaEmbedding,
483
+ handleEditRenderedMedia,
484
+ readOnly,
485
+ selected
381
486
  ]);
382
487
  const toolbarConfig = (0, external_react_namespaceObject.useMemo)(()=>{
383
488
  const actions = [
@@ -553,27 +658,30 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
553
658
  activeFormats: activeFormats,
554
659
  onFormat: handleFormat,
555
660
  onBlur: handleBlur,
556
- actions: formattingActions,
661
+ actions: effectiveFormattingActions,
557
662
  onAction: handleFormattingAction
558
663
  })
559
664
  ]
560
665
  }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_StickyNoteNode_styles_cjs_namespaceObject.StickyNoteMarkdown, {
561
666
  ref: markdownRef,
562
667
  ...scrollCaptureProps,
563
- children: localContent ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_markdown_default(), {
564
- remarkPlugins: [
565
- external_remark_gfm_default(),
566
- external_remark_breaks_default()
567
- ],
568
- components: markdownComponents,
569
- children: (0, external_StickyNoteNode_utils_cjs_namespaceObject.preserveNewlines)(localContent)
570
- }) : renderPlaceholderOnSelect && selected && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_markdown_default(), {
571
- remarkPlugins: [
572
- external_remark_gfm_default(),
573
- external_remark_breaks_default()
574
- ],
575
- components: markdownComponents,
576
- children: placeholder
668
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_StickyNoteMediaMarkdown_cjs_namespaceObject.StickyNoteMediaMarkdownProvider, {
669
+ value: mediaMarkdownOptions,
670
+ children: localContent ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_markdown_default(), {
671
+ remarkPlugins: [
672
+ external_remark_gfm_default(),
673
+ external_remark_breaks_default()
674
+ ],
675
+ components: markdownComponents,
676
+ children: (0, external_StickyNoteNode_utils_cjs_namespaceObject.preserveNewlines)(localContent)
677
+ }) : renderPlaceholderOnSelect && selected && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_markdown_default(), {
678
+ remarkPlugins: [
679
+ external_remark_gfm_default(),
680
+ external_remark_breaks_default()
681
+ ],
682
+ components: markdownComponents,
683
+ children: placeholder
684
+ })
577
685
  })
578
686
  })
579
687
  ]
@@ -635,6 +743,11 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
635
743
  })
636
744
  })
637
745
  ]
746
+ }),
747
+ enableMediaEmbedding && mediaDialog && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_StickyNoteMediaDialog_cjs_namespaceObject.StickyNoteMediaDialog, {
748
+ initialMedia: mediaDialog.token?.media,
749
+ onCancel: cancelMediaDialog,
750
+ onSubmit: submitMediaDialog
638
751
  })
639
752
  ]
640
753
  });
@@ -11,8 +11,9 @@ export interface StickyNoteNodeProps extends NodeProps {
11
11
  onResize?: (width: number, height: number) => void;
12
12
  onResizeStart?: () => void;
13
13
  onResizeEnd?: () => void;
14
+ enableMediaEmbedding?: boolean;
14
15
  formattingActions?: readonly StickyNoteFormattingAction[];
15
16
  markdownComponents?: Omit<Components, 'a'>;
16
17
  }
17
- export declare const StickyNoteNode: import("react").MemoExoticComponent<({ id, data, selected, dragging, placeholder, renderPlaceholderOnSelect, readOnly, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, formattingActions, markdownComponents: customMarkdownComponents, }: StickyNoteNodeProps) => import("react/jsx-runtime").JSX.Element>;
18
+ export declare const StickyNoteNode: import("react").MemoExoticComponent<({ id, data, selected, dragging, placeholder, renderPlaceholderOnSelect, readOnly, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, enableMediaEmbedding, formattingActions, markdownComponents: customMarkdownComponents, }: StickyNoteNodeProps) => import("react/jsx-runtime").JSX.Element>;
18
19
  //# sourceMappingURL=StickyNoteNode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StickyNoteNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/StickyNoteNode/StickyNoteNode.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAM1E,OAAsB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA8BhE,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,0BAA0B,EAE3B,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACpD,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC1D,kBAAkB,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;CAC5C;AA0iBD,eAAO,MAAM,cAAc,mQAthBxB,mBAAmB,6CAshBwE,CAAC"}
1
+ {"version":3,"file":"StickyNoteNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/StickyNoteNode/StickyNoteNode.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAM1E,OAAsB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA6ChE,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAEd,0BAA0B,EAE3B,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACpD,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAEzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC1D,kBAAkB,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;CAC5C;AA6qBD,eAAO,MAAM,cAAc,yRAhpBxB,mBAAmB,6CAgpBwE,CAAC"}
@@ -16,6 +16,9 @@ import { NodeViewportOverlay } from "../NodeViewportOverlay.js";
16
16
  import { NodeToolbar } from "../Toolbar/index.js";
17
17
  import { FormattingToolbar } from "./FormattingToolbar.js";
18
18
  import { activeFormatsEqual, continueListOnEnter, detectActiveFormats } from "./markdown-formatting/index.js";
19
+ import { findStickyNoteMediaAtSelection, insertStickyNoteMedia, parseStickyNoteMediaTokens, replaceStickyNoteMedia, serializeStickyNoteMedia } from "./StickyNoteMedia.js";
20
+ import { StickyNoteMediaDialog } from "./StickyNoteMediaDialog.js";
21
+ import { StickyNoteMediaMarkdownProvider, createStickyNoteMediaMarkdownComponents } from "./StickyNoteMediaMarkdown.js";
19
22
  import { BottomCornerIndicators, ColorOption, ColorPickerPanel, RESIZE_CONTROL_Z_INDEX, ResizeHandle, StickyNoteContainer, StickyNoteMarkdown, StickyNoteTextArea, StickyNoteWrapper, TopCornerIndicators, stickyNoteGlobalStyles } from "./StickyNoteNode.styles.js";
20
23
  import { STICKY_NOTE_COLORS, withAlpha } from "./StickyNoteNode.types.js";
21
24
  import { preserveNewlines, readTextSelection } from "./StickyNoteNode.utils.js";
@@ -23,13 +26,14 @@ import { useMarkdownShortcuts } from "./useMarkdownShortcuts.js";
23
26
  import { useScrollCapture } from "./useScrollCapture.js";
24
27
  const minWidth = 8 * GRID_SPACING;
25
28
  const minHeight = 8 * GRID_SPACING;
26
- const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = 'Add text', renderPlaceholderOnSelect = false, readOnly = false, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, formattingActions, markdownComponents: customMarkdownComponents })=>{
29
+ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = 'Add text', renderPlaceholderOnSelect = false, readOnly = false, onContentChange, onColorChange, onResize, onResizeStart, onResizeEnd, enableMediaEmbedding = false, formattingActions, markdownComponents: customMarkdownComponents })=>{
27
30
  const { _ } = useSafeLingui();
28
31
  const { updateNodeData, deleteElements } = useReactFlow();
29
32
  const { multipleNodesSelected } = useSelectionState();
30
33
  const [isEditing, setIsEditing] = useState(!readOnly && (data.autoFocus ?? false));
31
34
  const [isResizing, setIsResizing] = useState(false);
32
35
  const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);
36
+ const [mediaDialog, setMediaDialog] = useState(null);
33
37
  const [localContent, setLocalContent] = useState(data.content || '');
34
38
  const latestContentRef = useRef(localContent);
35
39
  const textAreaRef = useRef(null);
@@ -204,6 +208,92 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
204
208
  updateLocalContent,
205
209
  updateNodeData
206
210
  ]);
211
+ const openMediaDialog = useCallback((context)=>{
212
+ const { selection } = context;
213
+ setMediaDialog({
214
+ source: 'editor',
215
+ context,
216
+ token: findStickyNoteMediaAtSelection(selection.value, selection.selectionStart, selection.selectionEnd)
217
+ });
218
+ }, []);
219
+ const mediaFormattingAction = useMemo(()=>({
220
+ id: 'sticky-note-embed-media',
221
+ icon: /*#__PURE__*/ jsx(CanvasIcon, {
222
+ icon: "image-plus",
223
+ size: 14
224
+ }),
225
+ label: _({
226
+ id: 'sticky-note.media.embed-action',
227
+ message: 'Embed image or video'
228
+ }),
229
+ onAction: openMediaDialog
230
+ }), [
231
+ _,
232
+ openMediaDialog
233
+ ]);
234
+ const effectiveFormattingActions = useMemo(()=>enableMediaEmbedding ? [
235
+ mediaFormattingAction,
236
+ ...formattingActions ?? []
237
+ ] : formattingActions ?? [], [
238
+ enableMediaEmbedding,
239
+ formattingActions,
240
+ mediaFormattingAction
241
+ ]);
242
+ const handleEditRenderedMedia = useCallback((media, range)=>{
243
+ const sourceContent = latestContentRef.current;
244
+ const renderedTokens = parseStickyNoteMediaTokens(preserveNewlines(sourceContent));
245
+ const renderedIndex = renderedTokens.findIndex((token)=>token.start === range.start && token.end === range.end);
246
+ const sourceToken = renderedIndex >= 0 ? parseStickyNoteMediaTokens(sourceContent)[renderedIndex] : void 0;
247
+ setMediaDialog({
248
+ source: 'rendered',
249
+ token: sourceToken ?? {
250
+ media,
251
+ ...range
252
+ }
253
+ });
254
+ }, []);
255
+ const cancelMediaDialog = useCallback(()=>{
256
+ const current = mediaDialog;
257
+ setMediaDialog(null);
258
+ if (current?.source === 'editor') current.context.resume();
259
+ }, [
260
+ mediaDialog
261
+ ]);
262
+ useEffect(()=>{
263
+ if (!mediaDialog || enableMediaEmbedding && !readOnly) return;
264
+ setMediaDialog(null);
265
+ skipBlurRef.current = null;
266
+ if (!readOnly && 'editor' === mediaDialog.source) mediaDialog.context.resume();
267
+ }, [
268
+ enableMediaEmbedding,
269
+ mediaDialog,
270
+ readOnly
271
+ ]);
272
+ const submitMediaDialog = useCallback((media)=>{
273
+ if (!mediaDialog) return;
274
+ const block = serializeStickyNoteMedia(media);
275
+ if ('editor' === mediaDialog.source) {
276
+ const currentValue = mediaDialog.context.currentValue();
277
+ const next = mediaDialog.token ? replaceStickyNoteMedia(currentValue, mediaDialog.token, block) ?? insertStickyNoteMedia(currentValue, block, null) : insertStickyNoteMedia(currentValue, block, mediaDialog.context.selection);
278
+ setMediaDialog(null);
279
+ mediaDialog.context.commit(next);
280
+ return;
281
+ }
282
+ const currentValue = latestContentRef.current;
283
+ const next = replaceStickyNoteMedia(currentValue, mediaDialog.token, block) ?? insertStickyNoteMedia(currentValue, block, null);
284
+ setMediaDialog(null);
285
+ updateLocalContent(next.value);
286
+ onContentChange?.(next.value);
287
+ updateNodeData(id, {
288
+ content: next.value
289
+ });
290
+ }, [
291
+ id,
292
+ mediaDialog,
293
+ onContentChange,
294
+ updateLocalContent,
295
+ updateNodeData
296
+ ]);
207
297
  const updateActiveFormats = useCallback(()=>{
208
298
  if (!textAreaRef.current) return;
209
299
  const next = detectActiveFormats({
@@ -332,12 +422,27 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
332
422
  children: children
333
423
  })
334
424
  }), []);
425
+ const mediaMarkdownComponents = useMemo(()=>createStickyNoteMediaMarkdownComponents(customMarkdownComponents?.img), [
426
+ customMarkdownComponents?.img
427
+ ]);
335
428
  const markdownComponents = useMemo(()=>({
336
429
  ...customMarkdownComponents,
430
+ ...enableMediaEmbedding ? mediaMarkdownComponents : {},
337
431
  ...builtInMarkdownComponents
338
432
  }), [
339
433
  builtInMarkdownComponents,
340
- customMarkdownComponents
434
+ customMarkdownComponents,
435
+ enableMediaEmbedding,
436
+ mediaMarkdownComponents
437
+ ]);
438
+ const mediaMarkdownOptions = useMemo(()=>({
439
+ editable: enableMediaEmbedding && selected && !readOnly,
440
+ onEditMedia: handleEditRenderedMedia
441
+ }), [
442
+ enableMediaEmbedding,
443
+ handleEditRenderedMedia,
444
+ readOnly,
445
+ selected
341
446
  ]);
342
447
  const toolbarConfig = useMemo(()=>{
343
448
  const actions = [
@@ -513,27 +618,30 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
513
618
  activeFormats: activeFormats,
514
619
  onFormat: handleFormat,
515
620
  onBlur: handleBlur,
516
- actions: formattingActions,
621
+ actions: effectiveFormattingActions,
517
622
  onAction: handleFormattingAction
518
623
  })
519
624
  ]
520
625
  }) : /*#__PURE__*/ jsx(StickyNoteMarkdown, {
521
626
  ref: markdownRef,
522
627
  ...scrollCaptureProps,
523
- children: localContent ? /*#__PURE__*/ jsx(react_markdown, {
524
- remarkPlugins: [
525
- remark_gfm,
526
- remark_breaks
527
- ],
528
- components: markdownComponents,
529
- children: preserveNewlines(localContent)
530
- }) : renderPlaceholderOnSelect && selected && /*#__PURE__*/ jsx(react_markdown, {
531
- remarkPlugins: [
532
- remark_gfm,
533
- remark_breaks
534
- ],
535
- components: markdownComponents,
536
- children: placeholder
628
+ children: /*#__PURE__*/ jsx(StickyNoteMediaMarkdownProvider, {
629
+ value: mediaMarkdownOptions,
630
+ children: localContent ? /*#__PURE__*/ jsx(react_markdown, {
631
+ remarkPlugins: [
632
+ remark_gfm,
633
+ remark_breaks
634
+ ],
635
+ components: markdownComponents,
636
+ children: preserveNewlines(localContent)
637
+ }) : renderPlaceholderOnSelect && selected && /*#__PURE__*/ jsx(react_markdown, {
638
+ remarkPlugins: [
639
+ remark_gfm,
640
+ remark_breaks
641
+ ],
642
+ components: markdownComponents,
643
+ children: placeholder
644
+ })
537
645
  })
538
646
  })
539
647
  ]
@@ -595,6 +703,11 @@ const StickyNoteNodeComponent = ({ id, data, selected, dragging, placeholder = '
595
703
  })
596
704
  })
597
705
  ]
706
+ }),
707
+ enableMediaEmbedding && mediaDialog && /*#__PURE__*/ jsx(StickyNoteMediaDialog, {
708
+ initialMedia: mediaDialog.token?.media,
709
+ onCancel: cancelMediaDialog,
710
+ onSubmit: submitMediaDialog
598
711
  })
599
712
  ]
600
713
  });