@ai-matrx/rich-content 0.2.39 → 0.2.41

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.41
4
+
5
+ - **Copy is two rows.** `CopySplitButton`'s chevron menu is exactly "Copy markdown" and "Copy plain text"; the `mountMore` slot (the Alchemy palette under the chevron) is removed.
6
+ - **"Export…" holds the palette.** New `copy/ExportPalette` (`ExportPaletteAnchor`, `openExportPalette`, `hasExportPalette`) and the registry action `export-palette` ("Export…", ⋯ menu). `ActionBar` mounts the anchor at its ⋯; with `hideOverflow` the anchor is its own "Export…" icon. Formatted, JSON, download and AI are unchanged — they moved, nothing was removed.
7
+ - **One compact selection row.** The mode table gains `SELECTION_PRIMARY` (the only actions that take a button) and `SELECTION_MAX_VISIBLE = 6`. Reading: Copy · Highlight · Comment · Ask AI · More. Editing: Copy · Bold · Italic · Link · Ask AI · More. The five `selection:highlight-<colour>` ids are replaced by one `selection:highlight` that opens the colours.
8
+
9
+ **Consumer action:** stop passing `mountMore`; register one `selection:highlight` action (a colour panel) instead of five colour actions; a surface with no ⋯ menu renders `<ExportPaletteAnchor trigger controllerRef=…/>` beside its split Copy.
10
+
11
+ ## 0.2.40
12
+
13
+ - The selection toolbar's outer strip is `role="group"`, not a second `role=toolbar` wrapped around the real SelectionToolbar: one toolbar on screen.
14
+
15
+ **Consumer action:** none.
16
+
3
17
  ## 0.2.39
4
18
 
5
19
  - The selection toolbar's mode table knows `selection:format-color` (edit mode): text colour is a registered format action, so an editor whose engine has colour (the Spaces editor) offers it in the one toolbar instead of a second bubble.
@@ -7,8 +7,6 @@ export interface CopySplitButtonProps {
7
7
  label?: string;
8
8
  /** "sm" (32px, an action bar) or "xs" (28px, a dense strip). */
9
9
  size?: "sm" | "xs";
10
- /** Mount more copy options (the Alchemy palette) under the two rows; called with null on close. */
11
- mountMore?: (element: HTMLElement | null, close: () => void) => void;
12
10
  /**
13
11
  * Render only the chevron and its menu — for a host whose main control is already its own one-click
14
12
  * tile (the phone note dock). Same rows, same "Default" tag, same copy module; the host positions it
@@ -20,5 +18,5 @@ export interface CopySplitButtonProps {
20
18
  disabled?: boolean;
21
19
  className?: string;
22
20
  }
23
- export declare function CopySplitButton({ copy, label, size, mountMore, moreOnly, preserveSelection, disabled, className, }: CopySplitButtonProps): React.ReactElement;
21
+ export declare function CopySplitButton({ copy, label, size, moreOnly, preserveSelection, disabled, className, }: CopySplitButtonProps): React.ReactElement;
24
22
  export default CopySplitButton;
@@ -12,7 +12,6 @@ function CopySplitButton({
12
12
  copy,
13
13
  label = "Copy",
14
14
  size = "sm",
15
- mountMore,
16
15
  moreOnly = false,
17
16
  preserveSelection = false,
18
17
  disabled = false,
@@ -32,7 +31,6 @@ function CopySplitButton({
32
31
  if (timer.current) clearTimeout(timer.current);
33
32
  timer.current = setTimeout(() => setCopied(null), 1600);
34
33
  };
35
- const close = React.useCallback(() => setOpen(false), []);
36
34
  const keep = preserveSelection ? (event) => event.preventDefault() : void 0;
37
35
  const mainName = `${label} (${flavor === "text" ? "plain text" : "markdown"})`;
38
36
  const box = size === "xs" ? "h-7" : "h-8";
@@ -88,36 +86,33 @@ function CopySplitButton({
88
86
  children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
89
87
  }
90
88
  ) }),
91
- /* @__PURE__ */ jsxs(
89
+ /* @__PURE__ */ jsx(
92
90
  PopoverContent,
93
91
  {
94
92
  align: "start",
95
93
  className: "w-auto min-w-60 max-w-[min(24rem,calc(100vw-16px))] p-1",
96
94
  onOpenAutoFocus: preserveSelection ? (event) => event.preventDefault() : void 0,
97
95
  "data-copy-split-menu": "",
98
- children: [
99
- /* @__PURE__ */ jsx("div", { role: "menu", "aria-label": "Copy as", children: ROWS.map(({ flavor: rowFlavor, label: rowLabel, icon: Icon }) => /* @__PURE__ */ jsxs(
100
- "button",
101
- {
102
- type: "button",
103
- role: "menuitem",
104
- "data-copy-flavor": rowFlavor,
105
- onMouseDown: keep,
106
- onClick: () => {
107
- setOpen(false);
108
- void run(rowFlavor);
109
- },
110
- className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent",
111
- children: [
112
- /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
113
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: rowLabel }),
114
- rowFlavor === flavor ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Default" }) : null
115
- ]
96
+ children: /* @__PURE__ */ jsx("div", { role: "menu", "aria-label": "Copy as", children: ROWS.map(({ flavor: rowFlavor, label: rowLabel, icon: Icon }) => /* @__PURE__ */ jsxs(
97
+ "button",
98
+ {
99
+ type: "button",
100
+ role: "menuitem",
101
+ "data-copy-flavor": rowFlavor,
102
+ onMouseDown: keep,
103
+ onClick: () => {
104
+ setOpen(false);
105
+ void run(rowFlavor);
116
106
  },
117
- rowFlavor
118
- )) }),
119
- mountMore ? /* @__PURE__ */ jsx(MoreSlot, { mount: mountMore, close }) : null
120
- ]
107
+ className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent",
108
+ children: [
109
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
110
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: rowLabel }),
111
+ rowFlavor === flavor ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Default" }) : null
112
+ ]
113
+ },
114
+ rowFlavor
115
+ )) })
121
116
  }
122
117
  )
123
118
  ] })
@@ -125,24 +120,6 @@ function CopySplitButton({
125
120
  }
126
121
  );
127
122
  }
128
- function MoreSlot({ mount, close }) {
129
- const ref = React.useRef(null);
130
- React.useEffect(() => {
131
- const element = ref.current;
132
- try {
133
- mount(element, close);
134
- } catch (error) {
135
- console.error("[copy] more copy options could not open:", error);
136
- }
137
- return () => {
138
- try {
139
- mount(null, close);
140
- } catch {
141
- }
142
- };
143
- }, [mount, close]);
144
- return /* @__PURE__ */ jsx("div", { ref, "data-copy-split-more-slot": "", className: "mt-1 border-t border-border pt-1 empty:hidden" });
145
- }
146
123
  var CopySplitButton_default = CopySplitButton;
147
124
  export {
148
125
  CopySplitButton,
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ import type { ContentTransferController } from "@ai-matrx/alchemy/react/workspace";
3
+ /** Is an export palette mounted for this key (a ⋯ "Export…" row shows only then)? */
4
+ export declare function hasExportPalette(key: string): boolean;
5
+ /** Open the export palette mounted under `key`. False when nothing is mounted there. */
6
+ export declare function openExportPalette(key: string): boolean;
7
+ export interface ExportPaletteAnchorProps {
8
+ /** The key a ⋯ "Export…" row opens this palette by (the document's `instanceKey("alchemy")`). */
9
+ exportKey?: string;
10
+ /** The host's hidden ContentTransferMenu — the palette that mounts here. */
11
+ controllerRef: React.RefObject<ContentTransferController | null>;
12
+ /** Render a visible "Export…" icon button (a surface with no ⋯ menu of its own). */
13
+ trigger?: boolean;
14
+ /** What is exported, for the trigger's name ("Export note"). */
15
+ label?: string;
16
+ size?: "sm" | "xs";
17
+ className?: string;
18
+ }
19
+ export declare function ExportPaletteAnchor({ exportKey, controllerRef, trigger, label, size, className, }: ExportPaletteAnchorProps): React.ReactElement;
20
+ export default ExportPaletteAnchor;
@@ -0,0 +1,97 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Share } from "lucide-react";
5
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, cn } from "@ai-matrx/design-system";
6
+ const hosts = /* @__PURE__ */ new Map();
7
+ function hasExportPalette(key) {
8
+ return hosts.has(key);
9
+ }
10
+ function openExportPalette(key) {
11
+ const open = hosts.get(key);
12
+ if (!open) return false;
13
+ open();
14
+ return true;
15
+ }
16
+ function ExportPaletteAnchor({
17
+ exportKey,
18
+ controllerRef,
19
+ trigger = false,
20
+ label,
21
+ size = "sm",
22
+ className
23
+ }) {
24
+ const [open, setOpen] = React.useState(false);
25
+ React.useEffect(() => {
26
+ if (!exportKey) return;
27
+ const opener = () => {
28
+ window.setTimeout(() => setOpen(true), 0);
29
+ };
30
+ hosts.set(exportKey, opener);
31
+ return () => {
32
+ if (hosts.get(exportKey) === opener) hosts.delete(exportKey);
33
+ };
34
+ }, [exportKey]);
35
+ const close = React.useCallback(() => setOpen(false), []);
36
+ const name = `Export${label ? ` ${label}` : ""}\u2026`;
37
+ const box = size === "xs" ? "h-7 min-w-7" : "h-8 min-w-8";
38
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
39
+ trigger ? /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
40
+ "button",
41
+ {
42
+ type: "button",
43
+ "aria-label": name,
44
+ title: "Export\u2026",
45
+ "data-export-palette-trigger": "",
46
+ "data-matrx-button": "",
47
+ "data-tap-floor": "",
48
+ "data-tap-floor-square": "",
49
+ className: cn(
50
+ "inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground pointer-coarse:h-11 pointer-coarse:min-w-11",
51
+ box,
52
+ className
53
+ ),
54
+ children: /* @__PURE__ */ jsx(Share, { className: size === "xs" ? "h-3.5 w-3.5" : "h-4 w-4" })
55
+ }
56
+ ) }) : /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, "data-export-palette-anchor": "", className: cn("inline-block h-0 w-0", className) }) }),
57
+ /* @__PURE__ */ jsx(
58
+ PopoverContent,
59
+ {
60
+ align: "end",
61
+ className: "w-auto min-w-60 max-w-[min(24rem,calc(100vw-16px))] p-1",
62
+ "data-export-palette": "",
63
+ children: open ? /* @__PURE__ */ jsx(PaletteSlot, { controllerRef, close }) : null
64
+ }
65
+ )
66
+ ] });
67
+ }
68
+ function PaletteSlot({
69
+ controllerRef,
70
+ close
71
+ }) {
72
+ const ref = React.useRef(null);
73
+ const [failed, setFailed] = React.useState(null);
74
+ React.useEffect(() => {
75
+ const element = ref.current;
76
+ try {
77
+ if (!controllerRef.current) throw new Error("Export is unavailable here.");
78
+ controllerRef.current.mountPalette(element, close);
79
+ } catch (error) {
80
+ setFailed(error instanceof Error ? error.message : "Export is unavailable here.");
81
+ }
82
+ return () => {
83
+ try {
84
+ controllerRef.current?.mountPalette(null);
85
+ } catch {
86
+ }
87
+ };
88
+ }, [controllerRef, close]);
89
+ return /* @__PURE__ */ jsx("div", { ref, "data-export-palette-slot": "", children: failed ? /* @__PURE__ */ jsx("p", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: failed }) : null });
90
+ }
91
+ var ExportPalette_default = ExportPaletteAnchor;
92
+ export {
93
+ ExportPaletteAnchor,
94
+ ExportPalette_default as default,
95
+ hasExportPalette,
96
+ openExportPalette
97
+ };
@@ -0,0 +1,5 @@
1
+ import type { RichDocumentAction } from "../types.js";
2
+ export declare const EXPORT_PALETTE_ACTION_ID = "export-palette";
3
+ export declare const EXPORT_PALETTE_ACTION: RichDocumentAction;
4
+ /** Idempotent: the bar calls this on load. */
5
+ export declare function ensureExportPaletteAction(): void;
@@ -0,0 +1,26 @@
1
+ import { Share } from "lucide-react";
2
+ import { getAction, registerAction } from "./provider.js";
3
+ import { hasExportPalette, openExportPalette } from "../../copy/ExportPalette.js";
4
+ const EXPORT_PALETTE_ACTION_ID = "export-palette";
5
+ const EXPORT_PALETTE_ACTION = {
6
+ id: EXPORT_PALETTE_ACTION_ID,
7
+ label: "Export\u2026",
8
+ icon: Share,
9
+ category: "export",
10
+ supportedSources: "*",
11
+ renderSlot: "overflow",
12
+ order: 0,
13
+ visible: (ctx) => hasExportPalette(ctx.instanceKey("alchemy")),
14
+ run: (ctx) => {
15
+ openExportPalette(ctx.instanceKey("alchemy"));
16
+ }
17
+ };
18
+ function ensureExportPaletteAction() {
19
+ if (getAction(EXPORT_PALETTE_ACTION_ID)) return;
20
+ registerAction(EXPORT_PALETTE_ACTION);
21
+ }
22
+ export {
23
+ EXPORT_PALETTE_ACTION,
24
+ EXPORT_PALETTE_ACTION_ID,
25
+ ensureExportPaletteAction
26
+ };
@@ -7,8 +7,11 @@ import { cn } from "@ai-matrx/design-system";
7
7
  import { AlchemyDocumentMenu } from "./shared/AlchemyDocumentMenu.js";
8
8
  import { CopySplitButton } from "../../copy/CopySplitButton.js";
9
9
  import { copyRichContent } from "../../copy/copy-commands.js";
10
+ import { ExportPaletteAnchor } from "../../copy/ExportPalette.js";
11
+ import { ensureExportPaletteAction } from "../actions/export-palette-action.js";
10
12
  import { OpenOneMenuButton, useOneMenuFor } from "./shared/OpenOneMenuButton.js";
11
13
  import { StandaloneOneMenu } from "./shared/StandaloneOneMenu.js";
14
+ ensureExportPaletteAction();
12
15
  const BAR_RESTRICT = { exclude: ["copy"] };
13
16
  const SPLIT_COPY_ACTION_IDS = {
14
17
  markdown: "copy-markdown",
@@ -26,9 +29,6 @@ function ActionBar(props) {
26
29
  const hasCopy = actions.some((action) => action.category === "copy");
27
30
  const palette = React.useRef(null);
28
31
  const copy = React.useCallback((flavor) => runDocumentCopy(actions, getCtx, flavor), [actions, getCtx]);
29
- const mountMore = React.useCallback((element, close) => {
30
- palette.current?.mountPalette(element, close);
31
- }, []);
32
32
  return /* @__PURE__ */ jsxs(
33
33
  "div",
34
34
  {
@@ -43,7 +43,7 @@ function ActionBar(props) {
43
43
  ),
44
44
  children: [
45
45
  hasCopy ? /* @__PURE__ */ jsxs(Fragment, { children: [
46
- /* @__PURE__ */ jsx(CopySplitButton, { copy, size: mini ? "xs" : "sm", mountMore }),
46
+ /* @__PURE__ */ jsx(CopySplitButton, { copy, size: mini ? "xs" : "sm" }),
47
47
  /* @__PURE__ */ jsx(
48
48
  AlchemyDocumentMenu,
49
49
  {
@@ -67,6 +67,7 @@ function ActionBar(props) {
67
67
  hideOverflow: true
68
68
  }
69
69
  ),
70
+ hasCopy ? /* @__PURE__ */ jsx(ExportPaletteAnchor, { exportKey: sourceId, controllerRef: palette, trigger: hideOverflow, size: mini ? "xs" : "sm" }) : null,
70
71
  hideOverflow ? null : oneMenu ? /* @__PURE__ */ jsx(OpenOneMenuButton, { source: getCtx().source }) : /* @__PURE__ */ jsx(StandaloneOneMenu, { getCtx, target })
71
72
  ]
72
73
  }
@@ -185,10 +185,12 @@ function SelectionToolbarFrame({
185
185
  // ONE row: the split Copy first (copies the selection; markdown and
186
186
  // plain text one click away), then the Alchemy strip (formatting while
187
187
  // editing, highlight / comment / AI while reading).
188
+ // role="group": the inner SelectionToolbar is THE toolbar; a second
189
+ // role=toolbar here made two toolbars nested on screen.
188
190
  /* @__PURE__ */ jsxs(
189
191
  "div",
190
192
  {
191
- role: "toolbar",
193
+ role: "group",
192
194
  "aria-label": "Selection actions",
193
195
  "data-selection-strip": "",
194
196
  className: cn(
@@ -42,7 +42,8 @@ export declare function hostHalf<T>(target: ClickTarget, key: string): T | null;
42
42
  type ModeRule = readonly SelectionMode[] | ((knobs: SelectionToolbarKnobs) => readonly SelectionMode[]);
43
43
  /**
44
44
  * THE MODE TABLE. Editing: formatting + AI + comment. Reading: highlight,
45
- * comment, suggest, AI, link and report. AI shows in both.
45
+ * comment, suggest, AI, link and report. AI shows in both. WHERE each shows —
46
+ * a button or a More row — is `SELECTION_PRIMARY` below.
46
47
  */
47
48
  export declare const SELECTION_ACTION_MODES: Readonly<Record<string, ModeRule>>;
48
49
  /**
@@ -50,7 +51,7 @@ export declare const SELECTION_ACTION_MODES: Readonly<Record<string, ModeRule>>;
50
51
  * the census test checks against the providers (selection-host-kinds.test.ts):
51
52
  * a host kind is the set of host halves present on the target.
52
53
  *
53
- * annotated reading (annotation + context menu) highlight ×5, comment, suggest, link, report, AI and more —
54
+ * annotated reading (annotation + context menu) highlight, comment, Ask AI; More: suggest, link, report —
54
55
  * the study guide, document Annotate, and EVERY saved record
55
56
  * (annotations/RecordAnnotations): a note's preview, a chat
56
57
  * answer, the studio previewing an unedited saved document.
@@ -98,6 +99,16 @@ export interface SelectionCommonHost {
98
99
  messageId: string;
99
100
  }): void;
100
101
  }
102
+ /**
103
+ * THE BUTTONS (Arman, 2026-10-07: "simple, obvious, nothing extra"). The strip
104
+ * is the split Copy, these, then More — on every surface, desktop and phone.
105
+ * Every other action of the mode table is a More row.
106
+ * reading: Copy · Highlight (opens the colours) · Comment · Ask AI · More
107
+ * editing: Copy · Bold · Italic · Link · Ask AI · More (headings, lists, comment…)
108
+ */
109
+ export declare const SELECTION_PRIMARY: Readonly<Record<SelectionMode, readonly string[]>>;
110
+ /** The most controls the strip ever shows: the split Copy, the buttons, and More. */
111
+ export declare const SELECTION_MAX_VISIBLE = 6;
101
112
  /**
102
113
  * Which actions keep a button when the bar cannot show them all (a phone).
103
114
  * Everything else — including "AI and more" when space is tight — moves into
@@ -35,12 +35,8 @@ const SELECTION_ACTION_MODES = {
35
35
  "selection:format-codeblock": ["edit"],
36
36
  "selection:format-variable": ["edit"],
37
37
  "selection:format-color": ["edit"],
38
- // Annotations (the annotation sidecar)
39
- "selection:highlight-yellow": HIGHLIGHT,
40
- "selection:highlight-green": HIGHLIGHT,
41
- "selection:highlight-blue": HIGHLIGHT,
42
- "selection:highlight-pink": HIGHLIGHT,
43
- "selection:highlight-purple": HIGHLIGHT,
38
+ // Annotations (the annotation sidecar). ONE Highlight button; it opens the colour choice.
39
+ "selection:highlight": HIGHLIGHT,
44
40
  "selection:comment": ["read", "edit"],
45
41
  "selection:suggest": ["read"],
46
42
  "selection:link-record": ["read"],
@@ -85,6 +81,11 @@ function shownInSelectionMode(actionId, target) {
85
81
  return modes.includes(toolbar.mode);
86
82
  }
87
83
  const SELECTION_COMMON_HOST_KEY = "selectionCommon";
84
+ const SELECTION_PRIMARY = {
85
+ edit: ["selection:format-bold", "selection:format-italic", "selection:format-link", "selection:ai"],
86
+ read: ["selection:highlight", "selection:comment", "selection:ai"]
87
+ };
88
+ const SELECTION_MAX_VISIBLE = 6;
88
89
  const SELECTION_PRIORITY = {
89
90
  edit: [
90
91
  "selection:format-bold",
@@ -102,11 +103,7 @@ const SELECTION_PRIORITY = {
102
103
  "selection:format-quote",
103
104
  "selection:format-list",
104
105
  "selection:format-variable",
105
- "selection:highlight-yellow",
106
- "selection:highlight-green",
107
- "selection:highlight-blue",
108
- "selection:highlight-pink",
109
- "selection:highlight-purple",
106
+ "selection:highlight",
110
107
  "selection:table-row-above",
111
108
  "selection:table-col-left",
112
109
  "selection:table-align-left",
@@ -119,15 +116,11 @@ const SELECTION_PRIORITY = {
119
116
  "selection:save-to-table"
120
117
  ],
121
118
  read: [
122
- "selection:highlight-yellow",
119
+ "selection:highlight",
123
120
  "selection:comment",
124
121
  "selection:ai",
125
122
  "selection:suggest",
126
123
  "selection:tutor-explain",
127
- "selection:highlight-green",
128
- "selection:highlight-blue",
129
- "selection:highlight-pink",
130
- "selection:highlight-purple",
131
124
  "selection:tutor-ask",
132
125
  "selection:link-record",
133
126
  "selection:report",
@@ -165,8 +158,10 @@ function presentAt(id, target) {
165
158
  }
166
159
  function selectionPlacement(id, target) {
167
160
  const toolbar = selectionToolbarHostOf(target);
168
- if (!toolbar || toolbar.slots === null) return "primary";
169
- const shown = SELECTION_PRIORITY[toolbar.mode].filter((x) => presentAt(x, target));
161
+ if (!toolbar) return "primary";
162
+ if (!SELECTION_PRIMARY[toolbar.mode].includes(id)) return "overflow";
163
+ if (toolbar.slots === null) return "primary";
164
+ const shown = SELECTION_PRIMARY[toolbar.mode].filter((x) => presentAt(x, target));
170
165
  if (shown.length <= toolbar.slots) return "primary";
171
166
  const rank = shown.indexOf(id);
172
167
  return rank >= 0 && rank < Math.max(1, toolbar.slots - 1) ? "primary" : "overflow";
@@ -226,6 +221,8 @@ export {
226
221
  SELECTION_ACTION_MODES,
227
222
  SELECTION_COMMON_HOST_KEY,
228
223
  SELECTION_HOST_KINDS,
224
+ SELECTION_MAX_VISIBLE,
225
+ SELECTION_PRIMARY,
229
226
  SELECTION_PRIORITY,
230
227
  SELECTION_TOOLBAR_KNOB_FEATURE,
231
228
  declareSelectionProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/rich-content",
3
- "version": "0.2.39",
3
+ "version": "0.2.41",
4
4
  "description": "The AI Matrx formatted-text engine: the one markdown renderer, streaming markdown, the block splitter and renderer, the generic blocks, <RichContent> levels, the rich-document action registry and menus, copy, and the selection toolbar — as portable React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -130,21 +130,21 @@
130
130
  "unist-util-visit": "^5.1.0",
131
131
  "unist-util-visit-parents": "^6.0.2",
132
132
  "yaml": "^2.9.1",
133
+ "@ai-matrx/agents": "latest",
134
+ "@ai-matrx/alchemy": "latest",
133
135
  "@ai-matrx/canvas": "latest",
134
- "@ai-matrx/content-ir": "latest",
136
+ "@ai-matrx/data": "latest",
135
137
  "@ai-matrx/design-system": "latest",
136
- "@ai-matrx/alchemy": "latest",
138
+ "@ai-matrx/diff": "latest",
139
+ "@ai-matrx/content-ir": "latest",
140
+ "@ai-matrx/icons": "latest",
137
141
  "@ai-matrx/content-ir-react": "latest",
138
- "@ai-matrx/data": "latest",
139
142
  "@ai-matrx/kit": "latest",
140
- "@ai-matrx/icons": "latest",
141
- "@ai-matrx/diff": "latest",
142
- "@ai-matrx/media": "latest",
143
143
  "@ai-matrx/print": "latest",
144
144
  "@ai-matrx/records": "latest",
145
145
  "@ai-matrx/records-ui": "latest",
146
- "@ai-matrx/tap-target": "latest",
147
- "@ai-matrx/agents": "latest"
146
+ "@ai-matrx/media": "latest",
147
+ "@ai-matrx/tap-target": "latest"
148
148
  },
149
149
  "peerDependencies": {
150
150
  "react": ">=19.0.0",