@instructure/platform-block-content-editor 3.4.0 → 3.5.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.
package/README.md CHANGED
@@ -84,6 +84,16 @@ registry-driven insertion trays, hoists a single DnD context so blocks can be **
84
84
  tray onto the canvas, coordinates canvas↔panel selection focus, and routes a selected block to its
85
85
  settings form. It is **authoring-only** — see Preview below.
86
86
 
87
+ **RCE overlays and selection.** If the RCE you inject (via `RichTextEditorContext`, below) renders
88
+ overlays that portal outside the editor and take focus — the Canvas RCE's dialogs, trays, and menus
89
+ (word count, accessibility checker, content tray, keyboard shortcuts) all mount to `document.body` —
90
+ pass `isEditorOverlayOpen` to `BlockContentEditor`: a predicate that returns true while one is open.
91
+ Without it, opening one reads as "focus left the editor" and deselects the block, unmounting its
92
+ settings form (and your RCE). Only the host knows its RCE's overlay DOM, so the host owns the check
93
+ — the Canvas host queries canvas-rce's `[data-mce-component]` marker plus TinyMCE's
94
+ `.tox-menu` / `.tox-dialog` / `.tox-pop` floating-UI classes. A hand-composed sidebar passes the
95
+ same predicate to `useDesignerSelectionFocus`.
96
+
87
97
  ### Or compose the primitives yourself
88
98
 
89
99
  Every arrangement above is reproducible. Wrap your own layout in one `GridDndProvider` and drop a
@@ -138,7 +148,7 @@ Blocks and the editor read only from context; the host provides the implementati
138
148
  | `BrandColorContext` | the brand color (hex/`rgb()`), or `undefined` |
139
149
  | `BlockTranslationsProvider` | resolved strings per block + designer chrome (bundled English is the fallback) |
140
150
  | `RichTextRendererContext` | a renderer for RCE-authored HTML (read path); unset → sanitized fallback |
141
- | `RichTextEditorContext` | the RCE editor component (write path); unset → plain `TextArea` |
151
+ | `RichTextEditorContext` | the RCE editor component (write path); unset → plain `TextArea`. An RCE with overlays that portal outside the editor also needs `BlockContentEditor`'s `isEditorOverlayOpen` (see Write path) |
142
152
  | `AIActionContext` | the AI executor; **presence enables** the block-level AI, unset → hidden |
143
153
  | `BlockEditorApiProvider` | host data hooks — image/video/widget URLs and the settings-form file upload/delete |
144
154
 
@@ -27,6 +27,14 @@ export interface BlockContentEditorProps<HostToolId extends string = never> {
27
27
  height?: number | string;
28
28
  /** Shows the sidebar's rail collapse/expand toggle once a tool has been opened. */
29
29
  hasExpandPanelButton?: boolean;
30
+ /**
31
+ * Reports whether a host rich-text-editor overlay (a dialog, tray, or menu the RCE portals to
32
+ * `document.body` and gives focus to) is open. While it returns true, the canvas↔panel selection
33
+ * coordination holds the block rather than reading the overlay's focus-grab as "left the editor"
34
+ * and deselecting it. Wire it to the host's RCE overlay state. Without it, opening such an overlay
35
+ * deselects the block and unmounts its settings form. See `useDesignerSelectionFocus`.
36
+ */
37
+ isEditorOverlayOpen?: () => boolean;
30
38
  }
31
39
  /**
32
40
  * The authoring editor: the tool-panel sidebar over the drag-and-drop canvas, wired to the
@@ -39,5 +47,5 @@ export interface BlockContentEditorProps<HostToolId extends string = never> {
39
47
  * sources reach the canvas droppables. It is authoring-only — the student preview
40
48
  * (`PreviewArea`) is a separate export the host presents however it wants.
41
49
  */
42
- export declare function BlockContentEditor<HostToolId extends string = never>({ engine, registry, tools: hostTools, builtInToolIds, initialToolId, height, hasExpandPanelButton, }: BlockContentEditorProps<HostToolId>): import("react/jsx-runtime").JSX.Element;
50
+ export declare function BlockContentEditor<HostToolId extends string = never>({ engine, registry, tools: hostTools, builtInToolIds, initialToolId, height, hasExpandPanelButton, isEditorOverlayOpen, }: BlockContentEditorProps<HostToolId>): import("react/jsx-runtime").JSX.Element;
43
51
  //# sourceMappingURL=BlockContentEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlockContentEditor.d.ts","sourceRoot":"","sources":["../../src/editor/BlockContentEditor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,aAAa,CAAA;AAOnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAQjD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAE5E,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,+DAAgE,CAAA;AAC9F,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAmC9D,MAAM,WAAW,uBAAuB,CAAC,UAAU,SAAS,MAAM,GAAG,KAAK;IACxE;+FAC2F;IAC3F,MAAM,EAAE,yBAAyB,CAAA;IACjC,qGAAqG;IACrG,QAAQ,EAAE,aAAa,CAAA;IACvB;;;;wEAIoE;IACpE,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;IAC1B;;sCAEkC;IAClC,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;IAChC;qDACiD;IACjD,aAAa,CAAC,EAAE,aAAa,GAAG,UAAU,CAAA;IAC1C,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,SAAS,MAAM,GAAG,KAAK,EAAE,EACpE,MAAM,EACN,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,cAAuC,EACvC,aAAa,EACb,MAAM,EACN,oBAAoB,GACrB,EAAE,uBAAuB,CAAC,UAAU,CAAC,2CA+PrC"}
1
+ {"version":3,"file":"BlockContentEditor.d.ts","sourceRoot":"","sources":["../../src/editor/BlockContentEditor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,aAAa,CAAA;AAOnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAQjD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAE5E,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,+DAAgE,CAAA;AAC9F,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAmC9D,MAAM,WAAW,uBAAuB,CAAC,UAAU,SAAS,MAAM,GAAG,KAAK;IACxE;+FAC2F;IAC3F,MAAM,EAAE,yBAAyB,CAAA;IACjC,qGAAqG;IACrG,QAAQ,EAAE,aAAa,CAAA;IACvB;;;;wEAIoE;IACpE,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;IAC1B;;sCAEkC;IAClC,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;IAChC;qDACiD;IACjD,aAAa,CAAC,EAAE,aAAa,GAAG,UAAU,CAAA;IAC1C,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAA;CACpC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,SAAS,MAAM,GAAG,KAAK,EAAE,EACpE,MAAM,EACN,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,cAAuC,EACvC,aAAa,EACb,MAAM,EACN,oBAAoB,EACpB,mBAAmB,GACpB,EAAE,uBAAuB,CAAC,UAAU,CAAC,2CAgQrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fieldRenderers.d.ts","sourceRoot":"","sources":["../../../../src/editor/sidebar/form/fieldRenderers.tsx"],"names":[],"mappings":"AAoCA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,KAAK,aAAa,EAA2C,MAAM,sBAAsB,CAAA;AAQlG,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAghB3E,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,aAAa,EAAE,aAAa,CAiBtE,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAKjG"}
1
+ {"version":3,"file":"fieldRenderers.d.ts","sourceRoot":"","sources":["../../../../src/editor/sidebar/form/fieldRenderers.tsx"],"names":[],"mappings":"AAoCA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,KAAK,aAAa,EAA2C,MAAM,sBAAsB,CAAA;AAQlG,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AA+gB3E,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,aAAa,EAAE,aAAa,CAiBtE,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAKjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"VideoUploader.d.ts","sourceRoot":"","sources":["../../../../../src/editor/sidebar/form/uploaders/VideoUploader.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAE,KAAK,OAAO,EAAc,KAAK,WAAW,EAAiB,MAAM,iBAAiB,CAAA;AAS3F,UAAU,kBAAkB;IAC1B,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,kBAAkB,2CAsF3E"}
1
+ {"version":3,"file":"VideoUploader.d.ts","sourceRoot":"","sources":["../../../../../src/editor/sidebar/form/uploaders/VideoUploader.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAE,KAAK,OAAO,EAAc,KAAK,WAAW,EAAiB,MAAM,iBAAiB,CAAA;AAS3F,UAAU,kBAAkB;IAC1B,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,kBAAkB,2CAqF3E"}
@@ -11,8 +11,12 @@ import { FocusEvent, RefObject } from 'react';
11
11
  * - Focus enters a canvas item → clear `data-selected`, let `:focus-within` show the border.
12
12
  * - Focus leaves the canvas into the panel (or an open popover) → re-assert `data-selected`
13
13
  * on the last-focused item, so the selection stays visible while editing.
14
- * - Focus leaves both canvas and panel → deselect (clears `data-selected` and calls
15
- * `onDeselect`, which the caller wires to the engine's selection).
14
+ * - Focus leaves both canvas and panel → deselect (clears `data-selected` and calls `onDeselect`,
15
+ * which the caller wires to the engine's selection), UNLESS an editor-owned overlay is open. The
16
+ * package's own portaled popovers are matched by a DOM marker; a host rich-text editor's overlays
17
+ * (a dialog, tray, or menu canvas-rce portals to `document.body`, unmarked, and gives focus to)
18
+ * are reported by the host through `isEditorOverlayOpen`. While one is open the leave is held, so
19
+ * opening it keeps the block selected and its settings form mounted.
16
20
  * - Escape inside the canvas → deselect and blur.
17
21
  *
18
22
  * Spread `canvasProps` on the canvas wrapper (the element `canvasRef` points at) and
@@ -45,7 +49,17 @@ interface Options {
45
49
  canvasRef: RefObject<HTMLElement | null>;
46
50
  /** Called when focus leaves the editor entirely (or Escape) — clear the engine selection. */
47
51
  onDeselect: () => void;
52
+ /**
53
+ * Optional host predicate: true while an editor-owned overlay that lives outside the canvas and
54
+ * panel is open — a rich-text editor's dialog, tray, or menu that the host's RCE portals to
55
+ * `document.body` (unmarked, and takes focus). While it returns true a focus-leave is held rather
56
+ * than read as "left the editor", so opening such an overlay keeps the block selected. Only the
57
+ * host knows its RCE's overlay DOM, so only the host can report this. It is read a frame after
58
+ * focus leaves; a DOM query for the open overlay is reliable because the focus-leave that matters
59
+ * fires only once the overlay has taken focus, so the overlay's element is already in the DOM.
60
+ */
61
+ isEditorOverlayOpen?: () => boolean;
48
62
  }
49
- export declare function useDesignerSelectionFocus({ canvasRef, onDeselect, }: Options): DesignerSelectionFocusHandlers;
63
+ export declare function useDesignerSelectionFocus({ canvasRef, onDeselect, isEditorOverlayOpen, }: Options): DesignerSelectionFocusHandlers;
50
64
  export {};
51
65
  //# sourceMappingURL=useDesignerSelectionFocus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDesignerSelectionFocus.d.ts","sourceRoot":"","sources":["../../../src/editor/sidebar/useDesignerSelectionFocus.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAkC,MAAM,OAAO,CAAA;AAIvF;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE;QACX,cAAc,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;QACvC,aAAa,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;KACvC,CAAA;IACD,UAAU,EAAE;QACV,aAAa,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;QACtC,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD;;;;;;;;;OASG;IACH,oBAAoB,EAAE,MAAM,IAAI,CAAA;CACjC;AAED,UAAU,OAAO;IACf,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACxC,6FAA6F;IAC7F,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB;AAkBD,wBAAgB,yBAAyB,CAAC,EACxC,SAAS,EACT,UAAU,GACX,EAAE,OAAO,GAAG,8BAA8B,CA2J1C"}
1
+ {"version":3,"file":"useDesignerSelectionFocus.d.ts","sourceRoot":"","sources":["../../../src/editor/sidebar/useDesignerSelectionFocus.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAkC,MAAM,OAAO,CAAA;AAIvF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE;QACX,cAAc,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;QACvC,aAAa,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;KACvC,CAAA;IACD,UAAU,EAAE;QACV,aAAa,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;QACtC,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD;;;;;;;;;OASG;IACH,oBAAoB,EAAE,MAAM,IAAI,CAAA;CACjC;AAED,UAAU,OAAO;IACf,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACxC,6FAA6F;IAC7F,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAA;CACpC;AAkBD,wBAAgB,yBAAyB,CAAC,EACxC,SAAS,EACT,UAAU,EACV,mBAAmB,GACpB,EAAE,OAAO,GAAG,8BAA8B,CA8J1C"}