@brainfish-ai/editor 0.16.2 → 0.16.3

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 (39) hide show
  1. package/dist/{index-dKic9ff-.js → index-B7G61KeU.js} +1 -1
  2. package/dist/{index-CyTfufcP.js → index-BCU5wvMA.js} +2 -2
  3. package/dist/{index-paWgasj8.js → index-BgpucQu9.js} +3 -3
  4. package/dist/{index-BJKQPlcf.js → index-BrHQTa5O.js} +2 -2
  5. package/dist/{index-CsaeJbB5.js → index-Byx5Rin8.js} +2 -2
  6. package/dist/{index-BBMUH80b.js → index-CHiJxeZP.js} +2 -2
  7. package/dist/{index-DztBKea2.js → index-CSYZYQcP.js} +2 -2
  8. package/dist/{index-Dv14TLjz.js → index-CZ_tRMOP.js} +3 -3
  9. package/dist/{index-LyNcRvuh.js → index-CgxTSc3A.js} +2 -2
  10. package/dist/{index-COD_xliD.js → index-D3qfXl4a.js} +4 -4
  11. package/dist/{index-DveiglG-.js → index-DC8dl4wM.js} +3 -3
  12. package/dist/{index-BQa2bres.js → index-DHS4fqlV.js} +2 -2
  13. package/dist/{index-mEwvGwcX.js → index-D_WC_iU-.js} +2 -2
  14. package/dist/{index-C-bL3Cy9.js → index-DgawIQVL.js} +3 -3
  15. package/dist/{index-B4R1rT37.js → index-DysiDhtD.js} +2 -2
  16. package/dist/{index-DnpXm_wT.js → index-FrO1JgY0.js} +4 -4
  17. package/dist/{index-CgzQ1jj0.js → index-QwNEKxue.js} +2 -2
  18. package/dist/{index-DJWghCuI.js → index-f6Jh9zCn.js} +452 -159
  19. package/dist/{index-DnbjsrWF.js → index-hvx6Ru78.js} +2 -2
  20. package/dist/{index-D7noxe1h.js → index-ioAG3mIK.js} +3 -3
  21. package/dist/{index-DsUx-yKw.js → index-nC_e7r57.js} +2 -2
  22. package/dist/{index-CFr33LuW.js → index-wcyxRMSc.js} +2 -2
  23. package/dist/{index-Dk6UNQWp.js → index-wnkG3YUJ.js} +4 -4
  24. package/dist/{index-BIHNHMyg.js → index-xzCgWTs0.js} +2 -2
  25. package/dist/index.js +1 -1
  26. package/dist/markdown-source-editor/MarkdownSourceEditor.d.ts +2 -0
  27. package/dist/plugins/mentions/core/types.d.ts +2 -0
  28. package/dist/plugins/mentions/integration/slash-factory.d.ts +5 -0
  29. package/dist/plugins/mentions/integration/slash-keydown.d.ts +1 -0
  30. package/dist/plugins/mentions/ui/MentionSlashView.d.ts +1 -0
  31. package/dist/plugins/mentions/ui/filterMentionSlashRows.d.ts +16 -0
  32. package/dist/plugins/mentions/ui/loadMentionSlashMenu.d.ts +9 -0
  33. package/dist/plugins/mentions/ui/mentionSlashMenuState.d.ts +57 -0
  34. package/dist/plugins/mentions/ui/runtime.d.ts +5 -0
  35. package/dist/plugins/mentions/ui/useMentionSlashMenu.d.ts +8 -11
  36. package/dist/stories/mentionBreakFixtures.d.ts +11 -0
  37. package/dist/stories/storybook-utils.d.ts +4 -0
  38. package/dist/types.d.ts +8 -0
  39. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$2 } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import React__default, { createContext, useRef, useState, useMemo, useContext, useCallback, useLayoutEffect, useEffect, useId, Suspense, lazy } from 'react';
3
+ import React__default, { createContext, useRef, useState, useMemo, useContext, useCallback, useLayoutEffect, useEffect, useReducer, useId, Suspense, lazy } from 'react';
4
4
  import clsx from 'clsx';
5
5
  import { BrainfishColors } from '@brainfish-ai/components/colors';
6
6
  import * as Y from 'yjs';
@@ -8,7 +8,7 @@ import { UndoManager, Item as Item$1, ContentType, Text as Text$2, XmlElement, e
8
8
  import { flushSync, createPortal } from 'react-dom';
9
9
  import katex from 'katex';
10
10
  import { renderToStaticMarkup } from 'react-dom/server';
11
- import { Plus, Trash, SquaresFour, Warning, Info, Star, ArrowSquareOut, File as File$1, MagicWand, YoutubeLogo, Browser, X, Video, Paperclip, DownloadSimple, TextHOne, TextHSix, TextHFive, TextHFour, TextHThree, TextHTwo, Highlighter, ListBullets, ListNumbers, Link as Link$1, Eye, CodeSimple } from '@phosphor-icons/react';
11
+ import { Plus, Trash, SquaresFour, Warning, CaretLeft, CaretRight, ArrowSquareOut, Info, Star, File as File$1, MagicWand, YoutubeLogo, Browser, X, Video, Paperclip, DownloadSimple, TextHOne, TextHSix, TextHFive, TextHFour, TextHThree, TextHTwo, Highlighter, ListBullets, ListNumbers, Link as Link$1, Eye, CodeSimple } from '@phosphor-icons/react';
12
12
  import { Button } from '@brainfish-ai/components/ui/button';
13
13
  import { Input } from '@brainfish-ai/components/ui/input';
14
14
  import { ButtonGroup } from '@brainfish-ai/components/ui/button-group';
@@ -16,7 +16,7 @@ import { SimpleSelect } from '@brainfish-ai/components/select';
16
16
  import { Tooltip, TooltipTrigger, TooltipContent } from '@brainfish-ai/components/ui/tooltip';
17
17
  import { Command, CommandInput, CommandList, CommandGroup, CommandItem } from '@brainfish-ai/components/ui/command';
18
18
  import { Popover, PopoverTrigger, PopoverContent } from '@brainfish-ai/components/ui/popover';
19
- import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@brainfish-ai/components/ui/card';
19
+ import { Card, CardContent, CardFooter } from '@brainfish-ai/components/ui/card';
20
20
  import { Textarea } from '@brainfish-ai/components/ui/textarea';
21
21
  import { Tabs, TabsList, TabsTrigger, TabsContent } from '@brainfish-ai/components/ui/tabs';
22
22
 
@@ -41745,9 +41745,11 @@ function configureMentionStringify(crepe) {
41745
41745
  }
41746
41746
 
41747
41747
  const emptyRef = { current: [] };
41748
+ const emptyFooterButtonClickRef = { current: void 0 };
41748
41749
  const MentionsRuntimeContext = createContext({
41749
41750
  providersRef: emptyRef,
41750
- providers: []
41751
+ providers: [],
41752
+ onFooterButtonClickRef: emptyFooterButtonClickRef
41751
41753
  });
41752
41754
  function useMentionsRuntime() {
41753
41755
  return useContext(MentionsRuntimeContext);
@@ -41858,6 +41860,7 @@ const MentionNodeView = () => {
41858
41860
  className: clsx(
41859
41861
  MENTION_PILL_CLASS,
41860
41862
  "inline-flex relative top-0.5 items-center gap-1 rounded-full px-2 py-0.5 h-6 text-sm font-medium align-baseline",
41863
+ "max-w-64 min-w-0",
41861
41864
  { "bg-purple-800 text-purple-100 ring-purple-300": !invalid },
41862
41865
  { "bg-warning text-warning border border-warning ring-yellow-500": invalid },
41863
41866
  { "!ring-2": selected }
@@ -41878,8 +41881,8 @@ const MentionNodeView = () => {
41878
41881
  moveCaretOffMention(view, pos, node.nodeSize, event.key);
41879
41882
  },
41880
41883
  children: [
41881
- invalid ? /* @__PURE__ */ jsx(Warning, { size: 16, weight: "regular", "data-testid": "mention-pill-warning" }) : TypeIcon ? /* @__PURE__ */ jsx(TypeIcon, { size: 16, weight: "fill", "data-testid": "mention-pill-type-icon" }) : null,
41882
- parsed.label || parsed.type
41884
+ invalid ? /* @__PURE__ */ jsx(Warning, { size: 16, weight: "regular", className: "shrink-0", "data-testid": "mention-pill-warning" }) : TypeIcon ? /* @__PURE__ */ jsx(TypeIcon, { size: 16, weight: "fill", className: "shrink-0", "data-testid": "mention-pill-type-icon" }) : null,
41885
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", title: parsed.label || parsed.type, children: parsed.label || parsed.type })
41883
41886
  ]
41884
41887
  }
41885
41888
  ) }),
@@ -41917,6 +41920,30 @@ function configureMentionNodeView(ctx, nodeViewFactory) {
41917
41920
  ]);
41918
41921
  }
41919
41922
 
41923
+ const ALL_MENTION_GROUP = "all";
41924
+ function filterMentionSlashRows(rows, activeGroup) {
41925
+ if (activeGroup === ALL_MENTION_GROUP) return rows;
41926
+ return rows.filter((row) => row.groupLabel === activeGroup);
41927
+ }
41928
+ function resolveMentionSlashGroup(rows, activeGroup) {
41929
+ if (activeGroup === ALL_MENTION_GROUP) return ALL_MENTION_GROUP;
41930
+ return rows.some((row) => row.groupLabel === activeGroup) ? activeGroup : ALL_MENTION_GROUP;
41931
+ }
41932
+ function mentionSlashTabIds(rows) {
41933
+ const labels = [ALL_MENTION_GROUP];
41934
+ for (const row of rows) {
41935
+ if (!labels.includes(row.groupLabel)) labels.push(row.groupLabel);
41936
+ }
41937
+ return labels;
41938
+ }
41939
+ function cycleMentionSlashGroup(tabIds, current, direction) {
41940
+ if (!tabIds.length) return ALL_MENTION_GROUP;
41941
+ const resolved = tabIds.includes(current) ? current : ALL_MENTION_GROUP;
41942
+ const index = tabIds.indexOf(resolved);
41943
+ const delta = direction === "next" ? 1 : -1;
41944
+ return tabIds[(index + delta + tabIds.length) % tabIds.length] ?? ALL_MENTION_GROUP;
41945
+ }
41946
+
41920
41947
  //#region src/slash-plugin.ts
41921
41948
  function slashFactory(id) {
41922
41949
  const slashSpec = $ctx({}, `${id}_SLASH_SPEC`);
@@ -42712,7 +42739,10 @@ const mentionSlashApi = $ctx(
42712
42739
  isOpen: () => false,
42713
42740
  nav: () => {
42714
42741
  },
42742
+ navGroup: () => {
42743
+ },
42715
42744
  pick: () => false,
42745
+ focusFooterButton: () => false,
42716
42746
  dismiss: () => {
42717
42747
  }
42718
42748
  },
@@ -42781,34 +42811,135 @@ function firstSlashMessage(providers, kind) {
42781
42811
  return null;
42782
42812
  }
42783
42813
 
42814
+ async function loadMentionSlashMenu(providers, query, signal) {
42815
+ const decision = decideSlashFetch(providers);
42816
+ if (decision.kind === "loading") return { type: "retry" };
42817
+ if (decision.kind === "not-connected") {
42818
+ return { type: "not-connected", content: firstSlashMessage(providers, "not-connected") };
42819
+ }
42820
+ try {
42821
+ const settled = await Promise.allSettled(
42822
+ decision.ready.map(async (provider) => {
42823
+ const items = query ? await provider.search({ query, signal }) : await provider.list({ limit: 5, signal });
42824
+ return items.map(
42825
+ (item) => ({
42826
+ ...item,
42827
+ type: item.type || provider.type,
42828
+ groupLabel: provider.groupLabel,
42829
+ refAttr: provider.refAttr,
42830
+ provider
42831
+ })
42832
+ );
42833
+ })
42834
+ );
42835
+ if (signal.aborted) return { type: "retry" };
42836
+ const outcome = decideSlashFetchResult(settled);
42837
+ if (outcome === "error") {
42838
+ return { type: "error", content: firstSlashMessage(providers, "error") };
42839
+ }
42840
+ return {
42841
+ type: "loaded",
42842
+ rows: settled.flatMap((result) => result.status === "fulfilled" ? result.value : []),
42843
+ status: outcome
42844
+ };
42845
+ } catch (error) {
42846
+ if (signal.aborted) return { type: "retry" };
42847
+ if (error instanceof DOMException && error.name === "AbortError") return { type: "retry" };
42848
+ return { type: "error", content: firstSlashMessage(providers, "error") };
42849
+ }
42850
+ }
42851
+
42852
+ const initialMentionSlashMenuState = {
42853
+ open: false,
42854
+ query: "",
42855
+ status: "loading",
42856
+ slashContent: null,
42857
+ rows: [],
42858
+ selectedIndex: 0,
42859
+ activeGroup: ALL_MENTION_GROUP
42860
+ };
42861
+ function mentionSlashMenuReducer(state, action) {
42862
+ switch (action.type) {
42863
+ case "show": {
42864
+ const queryChanged = state.query !== action.query;
42865
+ if (state.open && !queryChanged) return state;
42866
+ return {
42867
+ ...state,
42868
+ open: true,
42869
+ query: action.query,
42870
+ ...queryChanged ? {
42871
+ activeGroup: ALL_MENTION_GROUP,
42872
+ selectedIndex: 0,
42873
+ status: "loading",
42874
+ rows: [],
42875
+ slashContent: null
42876
+ } : {}
42877
+ };
42878
+ }
42879
+ case "hide":
42880
+ return initialMentionSlashMenuState;
42881
+ case "loading":
42882
+ return { ...state, status: "loading", slashContent: null, rows: [] };
42883
+ case "not-connected":
42884
+ return { ...state, status: "not-connected", slashContent: action.content, rows: [] };
42885
+ case "error":
42886
+ return { ...state, status: "error", slashContent: action.content, rows: [] };
42887
+ case "loaded":
42888
+ return {
42889
+ ...state,
42890
+ rows: action.rows,
42891
+ status: action.status,
42892
+ slashContent: null,
42893
+ selectedIndex: 0,
42894
+ activeGroup: resolveMentionSlashGroup(action.rows, state.activeGroup)
42895
+ };
42896
+ case "select":
42897
+ return { ...state, selectedIndex: action.index };
42898
+ case "setGroup":
42899
+ return { ...state, activeGroup: action.group, selectedIndex: 0 };
42900
+ case "nav": {
42901
+ const visible = visibleMentionSlashRows(state);
42902
+ if (!visible.length) return state;
42903
+ const next = action.direction === "next" ? (state.selectedIndex + 1) % visible.length : (state.selectedIndex - 1 + visible.length) % visible.length;
42904
+ return { ...state, selectedIndex: next };
42905
+ }
42906
+ case "navGroup":
42907
+ return {
42908
+ ...state,
42909
+ activeGroup: cycleMentionSlashGroup(
42910
+ mentionSlashTabIds(state.rows),
42911
+ resolveMentionSlashGroup(state.rows, state.activeGroup),
42912
+ action.direction
42913
+ ),
42914
+ selectedIndex: 0
42915
+ };
42916
+ }
42917
+ }
42918
+ function visibleMentionSlashRows(state) {
42919
+ return filterMentionSlashRows(state.rows, resolveMentionSlashGroup(state.rows, state.activeGroup));
42920
+ }
42921
+ function resolvedMentionSlashGroup(state) {
42922
+ return resolveMentionSlashGroup(state.rows, state.activeGroup);
42923
+ }
42924
+
42784
42925
  const SEARCH_DEBOUNCE_MS = 200;
42785
42926
  const AVAILABILITY_RECHECK_MS = 200;
42786
42927
  function useMentionSlashMenu() {
42787
42928
  const { view } = usePluginViewContext();
42788
42929
  const { getInstance, loading } = useEditorAction();
42789
- const { providersRef } = useMentionsRuntime();
42930
+ const { providersRef, onFooterButtonClickRef } = useMentionsRuntime();
42790
42931
  const contentRef = useRef(null);
42932
+ const listRef = useRef(null);
42791
42933
  const providerRef = useRef(null);
42792
42934
  const viewRef = useRef(view);
42793
42935
  viewRef.current = view;
42794
- const listRef = useRef(null);
42795
- const [open, setOpen] = useState(false);
42796
- const [query, setQuery] = useState("");
42797
- const [status, setStatus] = useState("loading");
42798
- const [slashContent, setSlashContent] = useState(null);
42799
- const [rows, setRows] = useState([]);
42800
- const [selectedIndex, setSelectedIndex] = useState(0);
42801
- const [availabilityTick, setAvailabilityTick] = useState(0);
42802
42936
  const fromToRef = useRef({ from: 0, to: 0 });
42803
- const rowsRef = useRef(rows);
42804
- rowsRef.current = rows;
42805
- const selectedIndexRef = useRef(selectedIndex);
42806
- selectedIndexRef.current = selectedIndex;
42807
- const statusRef = useRef(status);
42808
- statusRef.current = status;
42809
- const openRef = useRef(open);
42810
- openRef.current = open;
42811
42937
  const hostRef = useRef(null);
42938
+ const [state, dispatch] = useReducer(mentionSlashMenuReducer, initialMentionSlashMenuState);
42939
+ const stateRef = useRef(state);
42940
+ stateRef.current = state;
42941
+ const visibleRows = visibleMentionSlashRows(state);
42942
+ const activeGroup = resolvedMentionSlashGroup(state);
42812
42943
  useLayoutEffect(() => {
42813
42944
  const el = contentRef.current;
42814
42945
  if (el?.parentElement && el.parentElement !== document.body) {
@@ -42823,10 +42954,11 @@ function useMentionSlashMenu() {
42823
42954
  };
42824
42955
  }, []);
42825
42956
  const pickRef = useRef(() => false);
42826
- pickRef.current = () => {
42827
- const row = rowsRef.current[selectedIndexRef.current];
42957
+ pickRef.current = (index) => {
42958
+ const current = stateRef.current;
42959
+ const row = visibleMentionSlashRows(current)[index ?? current.selectedIndex];
42828
42960
  const editorView = viewRef.current;
42829
- if (statusRef.current !== "ready") return false;
42961
+ if (current.status !== "ready") return false;
42830
42962
  if (!row || !editorView || !editorView.editable) return false;
42831
42963
  const inserted = insertMentionInView(editorView, fromToRef.current.from, fromToRef.current.to, row, row.provider);
42832
42964
  if (inserted) providerRef.current?.hide();
@@ -42842,141 +42974,187 @@ function useMentionSlashMenu() {
42842
42974
  root: document.body,
42843
42975
  floatingUIOptions: { strategy: "fixed" },
42844
42976
  shouldShow(editorView) {
42977
+ if (contentRef.current?.contains(document.activeElement)) return true;
42845
42978
  if (!editorView.editable) return false;
42846
42979
  if (!providersRef.current.length) return false;
42847
42980
  const trigger = findMentionTrigger(editorView.state);
42848
42981
  if (!trigger) return false;
42849
42982
  fromToRef.current = { from: trigger.from, to: trigger.to };
42850
- queueMicrotask(() => {
42851
- setQuery(trigger.query);
42852
- setOpen(true);
42853
- });
42983
+ queueMicrotask(() => dispatch({ type: "show", query: trigger.query }));
42854
42984
  return true;
42855
42985
  }
42856
42986
  });
42857
42987
  slashProvider.onHide = () => {
42858
- queueMicrotask(() => {
42859
- setOpen(false);
42860
- setRows([]);
42861
- setSlashContent(null);
42862
- setStatus("loading");
42863
- });
42988
+ queueMicrotask(() => dispatch({ type: "hide" }));
42864
42989
  };
42865
42990
  providerRef.current = slashProvider;
42866
42991
  const onNativeMouseDown = (event) => {
42867
42992
  if (!viewRef.current?.editable) return;
42868
- const option = event.target instanceof Element ? event.target.closest("[data-mention-option-index]") : null;
42993
+ const target = event.target instanceof Element ? event.target : null;
42994
+ const tabNav = target?.closest("[data-mention-tab-nav]");
42995
+ if (tabNav) {
42996
+ event.preventDefault();
42997
+ event.stopPropagation();
42998
+ const direction = tabNav.getAttribute("data-mention-tab-nav");
42999
+ if (direction === "next" || direction === "prev") dispatch({ type: "navGroup", direction });
43000
+ return;
43001
+ }
43002
+ const tab = target?.closest("[data-mention-group]");
43003
+ if (tab) {
43004
+ event.preventDefault();
43005
+ event.stopPropagation();
43006
+ const group = tab.getAttribute("data-mention-group");
43007
+ if (group) dispatch({ type: "setGroup", group });
43008
+ return;
43009
+ }
43010
+ const option = target?.closest("[data-mention-option-index]");
42869
43011
  if (!option) return;
42870
43012
  event.preventDefault();
42871
43013
  event.stopPropagation();
42872
43014
  const index = Number(option.getAttribute("data-mention-option-index"));
42873
43015
  if (!Number.isFinite(index)) return;
42874
- selectedIndexRef.current = index;
42875
- setSelectedIndex(index);
42876
- pickRef.current();
43016
+ dispatch({ type: "select", index });
43017
+ pickRef.current(index);
43018
+ };
43019
+ const onNativeKeyDown = (event) => {
43020
+ const target = event.target instanceof Element ? event.target : null;
43021
+ if (!target?.closest('[data-testid="mention-slash-footer-button"]')) return;
43022
+ if (event.key === "Escape") {
43023
+ event.preventDefault();
43024
+ event.stopPropagation();
43025
+ viewRef.current?.focus();
43026
+ providerRef.current?.hide();
43027
+ return;
43028
+ }
43029
+ if (event.key === "Tab") {
43030
+ event.preventDefault();
43031
+ viewRef.current?.focus();
43032
+ }
43033
+ };
43034
+ const onNativeClick = (event) => {
43035
+ const target = event.target instanceof Element ? event.target : null;
43036
+ if (!target?.closest('[data-testid="mention-slash-footer-button"]')) return;
43037
+ onFooterButtonClickRef.current?.();
42877
43038
  };
42878
43039
  content.addEventListener("mousedown", onNativeMouseDown);
43040
+ content.addEventListener("keydown", onNativeKeyDown);
43041
+ content.addEventListener("click", onNativeClick);
42879
43042
  return () => {
42880
43043
  content.removeEventListener("mousedown", onNativeMouseDown);
43044
+ content.removeEventListener("keydown", onNativeKeyDown);
43045
+ content.removeEventListener("click", onNativeClick);
42881
43046
  slashProvider.destroy();
42882
43047
  providerRef.current = null;
42883
43048
  };
42884
- }, [view, providersRef]);
43049
+ }, [view, providersRef, onFooterButtonClickRef]);
43050
+ const prevEditorStateRef = useRef(void 0);
42885
43051
  useEffect(() => {
42886
43052
  if (!view || !providerRef.current) return;
42887
- providerRef.current.update(view);
43053
+ providerRef.current.update(view, prevEditorStateRef.current);
43054
+ prevEditorStateRef.current = view.state;
42888
43055
  });
42889
43056
  useEffect(() => {
42890
- if (!open) return;
43057
+ if (!state.open) return;
42891
43058
  const abort = new AbortController();
42892
43059
  let recheckTimer;
42893
- const run = debounce(async () => {
42894
- const providers = providersRef.current;
42895
- const decision = decideSlashFetch(providers);
42896
- if (decision.kind === "loading") {
42897
- setRows([]);
42898
- setSlashContent(null);
42899
- setStatus("loading");
42900
- recheckTimer = setTimeout(() => setAvailabilityTick((tick) => tick + 1), AVAILABILITY_RECHECK_MS);
42901
- return;
42902
- }
42903
- if (decision.kind === "not-connected") {
42904
- setRows([]);
42905
- setSlashContent(firstSlashMessage(providers, "not-connected"));
42906
- setStatus("not-connected");
43060
+ const load = async () => {
43061
+ const result = await loadMentionSlashMenu(providersRef.current, state.query, abort.signal);
43062
+ if (abort.signal.aborted) return;
43063
+ if (result.type === "retry") {
43064
+ dispatch({ type: "loading" });
43065
+ recheckTimer = setTimeout(() => {
43066
+ void load();
43067
+ }, AVAILABILITY_RECHECK_MS);
42907
43068
  return;
42908
43069
  }
42909
- setSlashContent(null);
42910
- setStatus("loading");
42911
- try {
42912
- const settled = await Promise.allSettled(
42913
- decision.ready.map(async (provider) => {
42914
- const items = query ? await provider.search({ query, signal: abort.signal }) : await provider.list({ limit: 5, signal: abort.signal });
42915
- return items.map((item) => ({
42916
- ...item,
42917
- type: item.type || provider.type,
42918
- groupLabel: provider.groupLabel,
42919
- refAttr: provider.refAttr,
42920
- provider
42921
- }));
42922
- })
42923
- );
42924
- if (abort.signal.aborted) return;
42925
- const outcome = decideSlashFetchResult(settled);
42926
- if (outcome === "error") {
42927
- setRows([]);
42928
- setSlashContent(firstSlashMessage(providers, "error"));
42929
- setStatus("error");
42930
- return;
42931
- }
42932
- const next = settled.flatMap((result) => result.status === "fulfilled" ? result.value : []);
42933
- setRows(next);
42934
- setSelectedIndex(0);
42935
- setSlashContent(null);
42936
- setStatus(outcome);
42937
- } catch (error) {
42938
- if (abort.signal.aborted) return;
42939
- if (error instanceof DOMException && error.name === "AbortError") return;
42940
- setRows([]);
42941
- setSlashContent(firstSlashMessage(providersRef.current, "error"));
42942
- setStatus("error");
42943
- }
42944
- }, SEARCH_DEBOUNCE_MS);
43070
+ dispatch(result);
43071
+ };
43072
+ const run = debounce(load, SEARCH_DEBOUNCE_MS);
42945
43073
  void run();
42946
43074
  return () => {
42947
43075
  abort.abort();
42948
43076
  run.cancel();
42949
43077
  clearTimeout(recheckTimer);
42950
43078
  };
42951
- }, [open, query, providersRef, availabilityTick]);
43079
+ }, [state.open, state.query, providersRef]);
42952
43080
  useEffect(() => {
42953
43081
  const ctx = getInstance()?.ctx;
42954
43082
  if (!ctx) return;
42955
43083
  ctx.set(mentionSlashApi.key, {
42956
- isOpen: () => openRef.current,
42957
- nav: (direction) => {
42958
- const items = rowsRef.current;
42959
- if (!items.length) return;
42960
- setSelectedIndex((index) => direction === "next" ? (index + 1) % items.length : (index - 1 + items.length) % items.length);
42961
- },
43084
+ isOpen: () => stateRef.current.open,
43085
+ nav: (direction) => dispatch({ type: "nav", direction }),
43086
+ navGroup: (direction) => dispatch({ type: "navGroup", direction }),
42962
43087
  pick: () => pickRef.current(),
43088
+ focusFooterButton: () => {
43089
+ const button = contentRef.current?.querySelector('[data-testid="mention-slash-footer-button"]');
43090
+ if (!button) return false;
43091
+ button.focus({ focusVisible: true });
43092
+ return true;
43093
+ },
42963
43094
  dismiss: () => providerRef.current?.hide()
42964
43095
  });
42965
43096
  }, [getInstance, loading]);
42966
43097
  useLayoutEffect(() => {
42967
43098
  listRef.current?.querySelector('[data-selected="true"]')?.scrollIntoView({ block: "nearest" });
42968
- }, [selectedIndex]);
42969
- return { contentRef, listRef, open, query, status, slashContent, rows, selectedIndex };
43099
+ }, [state.selectedIndex]);
43100
+ return {
43101
+ contentRef,
43102
+ listRef,
43103
+ open: state.open,
43104
+ query: state.query,
43105
+ status: state.status,
43106
+ slashContent: state.slashContent,
43107
+ rows: state.rows,
43108
+ visibleRows,
43109
+ selectedIndex: state.selectedIndex,
43110
+ activeGroup,
43111
+ setActiveGroup: (group) => dispatch({ type: "setGroup", group })
43112
+ };
42970
43113
  }
42971
43114
 
42972
43115
  const MentionSlashView = () => {
42973
- const { contentRef, listRef, open, query, status, slashContent, rows, selectedIndex } = useMentionSlashMenu();
42974
- const grouped = groupRows(rows);
42975
- const activeId = rows[selectedIndex] ? `bf-mention-opt-${selectedIndex}` : void 0;
42976
- const selectedRow = rows[selectedIndex];
42977
- const activeGroup = grouped.find((group) => selectedRow != null && group.rows.includes(selectedRow));
42978
- const activeGroupIndex = activeGroup && selectedRow ? activeGroup.rows.indexOf(selectedRow) : 0;
42979
- const activeGroupCount = activeGroup?.rows.length ?? 0;
43116
+ const { footerButtonLabel } = useMentionsRuntime();
43117
+ const {
43118
+ contentRef,
43119
+ listRef,
43120
+ open,
43121
+ query,
43122
+ status,
43123
+ slashContent,
43124
+ rows,
43125
+ visibleRows,
43126
+ selectedIndex,
43127
+ activeGroup,
43128
+ setActiveGroup
43129
+ } = useMentionSlashMenu();
43130
+ const grouped = groupRows(visibleRows);
43131
+ const tabGroups = groupRows(rows);
43132
+ const activeId = visibleRows[selectedIndex] ? `bf-mention-opt-${selectedIndex}` : void 0;
43133
+ const tabsRef = useRef(null);
43134
+ const [canScrollLeft, setCanScrollLeft] = useState(false);
43135
+ const [canScrollRight, setCanScrollRight] = useState(false);
43136
+ const measureTabs = useCallback(() => {
43137
+ const node = tabsRef.current;
43138
+ if (!node) return;
43139
+ setCanScrollLeft(node.scrollLeft > 1);
43140
+ setCanScrollRight(node.scrollLeft + node.clientWidth < node.scrollWidth - 1);
43141
+ }, []);
43142
+ useLayoutEffect(() => {
43143
+ const node = tabsRef.current;
43144
+ if (!node) return;
43145
+ measureTabs();
43146
+ const observer = new ResizeObserver(measureTabs);
43147
+ observer.observe(node);
43148
+ node.addEventListener("scroll", measureTabs, { passive: true });
43149
+ return () => {
43150
+ observer.disconnect();
43151
+ node.removeEventListener("scroll", measureTabs);
43152
+ };
43153
+ }, [tabGroups, open, status, measureTabs]);
43154
+ useLayoutEffect(() => {
43155
+ const tab = tabsRef.current?.querySelector(`[data-mention-group="${CSS.escape(activeGroup)}"]`);
43156
+ tab?.scrollIntoView({ inline: "nearest", block: "nearest", behavior: "smooth" });
43157
+ }, [activeGroup]);
42980
43158
  return /* @__PURE__ */ jsx(
42981
43159
  "div",
42982
43160
  {
@@ -42991,26 +43169,78 @@ const MentionSlashView = () => {
42991
43169
  role: "listbox",
42992
43170
  "aria-label": "Mentions",
42993
43171
  "aria-activedescendant": activeId,
42994
- className: "text-xs p-1.5 w-96",
43172
+ className: "text-xs p-1.5 w-80 max-w-full min-w-0 overflow-hidden",
42995
43173
  children: [
42996
43174
  status === "loading" && /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-muted-foreground", children: "Loading…" }),
42997
43175
  (status === "error" || status === "not-connected") && /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-muted-foreground", children: slashContent }),
42998
- status === "empty" && /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-muted-foreground", children: "No matches" }),
43176
+ status === "empty" && /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-muted-foreground", children: query.trim() ? "No matches" : "No mentions yet" }),
42999
43177
  status === "ready" && /* @__PURE__ */ jsxs(Fragment$2, { children: [
43000
- /* @__PURE__ */ jsx(CardHeader, { className: "p-2 pt-1.5", children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex justify-between", children: [
43001
- /* @__PURE__ */ jsx("span", { className: "uppercase", children: activeGroup?.label }),
43002
- query ? /* @__PURE__ */ jsxs("span", { "data-testid": "mention-slash-counter", children: [
43003
- activeGroupIndex + 1,
43004
- " of ",
43005
- activeGroupCount
43178
+ /* @__PURE__ */ jsxs("div", { className: "relative min-w-0 max-w-full overflow-hidden border-b border-border", children: [
43179
+ /* @__PURE__ */ jsxs(
43180
+ "div",
43181
+ {
43182
+ ref: tabsRef,
43183
+ className: "flex w-full min-w-0 flex-nowrap overflow-x-auto overflow-y-hidden scroll-smooth [scrollbar-width:none]",
43184
+ children: [
43185
+ /* @__PURE__ */ jsx(
43186
+ GroupTab,
43187
+ {
43188
+ groupId: ALL_MENTION_GROUP,
43189
+ label: "All",
43190
+ count: rows.length,
43191
+ selected: activeGroup === ALL_MENTION_GROUP,
43192
+ onSelect: () => setActiveGroup(ALL_MENTION_GROUP)
43193
+ }
43194
+ ),
43195
+ tabGroups.map((group) => /* @__PURE__ */ jsx(
43196
+ GroupTab,
43197
+ {
43198
+ groupId: group.label,
43199
+ label: group.label,
43200
+ count: group.rows.length,
43201
+ selected: activeGroup === group.label,
43202
+ onSelect: () => setActiveGroup(group.label)
43203
+ },
43204
+ group.label
43205
+ ))
43206
+ ]
43207
+ }
43208
+ ),
43209
+ canScrollLeft ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
43210
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 w-8 bg-gradient-to-r from-card to-transparent" }),
43211
+ /* @__PURE__ */ jsx(
43212
+ "button",
43213
+ {
43214
+ type: "button",
43215
+ "aria-label": "Previous mention group",
43216
+ "data-mention-tab-nav": "prev",
43217
+ className: "absolute inset-y-0 left-0 z-10 px-0.5 text-muted-foreground",
43218
+ onMouseDown: (event) => event.preventDefault(),
43219
+ children: /* @__PURE__ */ jsx(CaretLeft, { size: 14 })
43220
+ }
43221
+ )
43222
+ ] }) : null,
43223
+ canScrollRight ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
43224
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-card to-transparent" }),
43225
+ /* @__PURE__ */ jsx(
43226
+ "button",
43227
+ {
43228
+ type: "button",
43229
+ "aria-label": "Next mention group",
43230
+ "data-mention-tab-nav": "next",
43231
+ className: "absolute inset-y-0 right-0 z-10 px-0.5 text-muted-foreground",
43232
+ onMouseDown: (event) => event.preventDefault(),
43233
+ children: /* @__PURE__ */ jsx(CaretRight, { size: 14 })
43234
+ }
43235
+ )
43006
43236
  ] }) : null
43007
- ] }) }),
43237
+ ] }),
43008
43238
  /* @__PURE__ */ jsx(CardContent, { className: "p-0 max-h-72 overflow-y-auto", children: grouped.map((group, groupIndex) => /* @__PURE__ */ jsxs("div", { children: [
43009
- grouped.length > 1 && /* @__PURE__ */ jsx("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: group.label }),
43239
+ activeGroup === ALL_MENTION_GROUP && grouped.length > 1 && /* @__PURE__ */ jsx("div", { className: "px-2 py-1 text-xs text-muted-foreground truncate", title: group.label, children: group.label }),
43010
43240
  group.rows.map((row) => {
43011
- const index = rows.indexOf(row);
43241
+ const index = visibleRows.indexOf(row);
43012
43242
  const selected = index === selectedIndex;
43013
- const TypeIcon = row.provider.typeIcon;
43243
+ const TypeIcon = row.icon ?? row.provider.typeIcon;
43014
43244
  return /* @__PURE__ */ jsxs(
43015
43245
  "div",
43016
43246
  {
@@ -43019,25 +43249,37 @@ const MentionSlashView = () => {
43019
43249
  "aria-selected": selected,
43020
43250
  "data-selected": selected ? "true" : void 0,
43021
43251
  "data-mention-option-index": index,
43022
- className: `cursor-pointer grid grid-cols-[24px_minmax(0,1fr)_auto] gap-[2px_8px] items-center p-2 ${selected ? "bg-dark-200" : ""}`,
43252
+ className: `cursor-pointer flex min-w-0 items-center gap-2 p-2 ${selected ? "bg-dark-200" : ""}`,
43023
43253
  children: [
43254
+ /* @__PURE__ */ jsx(TypeIcon, { size: 16, weight: "fill", className: "shrink-0 text-subtle" }),
43024
43255
  /* @__PURE__ */ jsx(
43025
43256
  "span",
43026
43257
  {
43027
- className: `size-6 rounded-md grid place-items-center bg-purple-800 text-purple-100 ${row.description ? "row-span-2" : ""}`,
43028
- children: /* @__PURE__ */ jsx(TypeIcon, { size: 12, weight: "fill" })
43258
+ className: "min-w-0 flex-1 font-semibold text-sm overflow-hidden text-ellipsis whitespace-nowrap",
43259
+ title: row.label,
43260
+ children: row.label
43029
43261
  }
43030
- ),
43031
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm overflow-hidden text-ellipsis whitespace-nowrap", children: row.label }),
43032
- /* @__PURE__ */ jsx("span", { className: "text-xs text-subtlest whitespace-nowrap tabular-nums", children: row.inputCount ? `${row.inputCount} inputs` : null }),
43033
- row.description ? /* @__PURE__ */ jsx("span", { className: "col-start-2 col-span-2 text-xs text-subtlest overflow-hidden text-ellipsis whitespace-nowrap", children: row.description }) : null
43262
+ )
43034
43263
  ]
43035
43264
  },
43036
43265
  `${row.type}-${row.id}-${index}`
43037
43266
  );
43038
43267
  })
43039
43268
  ] }, `${group.label}-${groupIndex}`)) }),
43040
- /* @__PURE__ */ jsx(CardFooter, { className: "p-2 pb-1 border-t border-border", children: /* @__PURE__ */ jsx("span", { className: "text-xs text-subtlest", children: "↑↓ to move · Enter to insert · Esc to close" }) })
43269
+ /* @__PURE__ */ jsx(CardFooter, { className: "p-2 pb-1 border-t border-border min-w-0", children: /* @__PURE__ */ jsxs(
43270
+ Button,
43271
+ {
43272
+ type: "button",
43273
+ variant: "link",
43274
+ size: "sm",
43275
+ className: "h-auto max-w-full min-w-0 p-0 text-lime-700 font-normal whitespace-nowrap",
43276
+ "data-testid": "mention-slash-footer-button",
43277
+ children: [
43278
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: footerButtonLabel ?? "Create a workflow" }),
43279
+ /* @__PURE__ */ jsx(ArrowSquareOut, { size: 14, className: "shrink-0" })
43280
+ ]
43281
+ }
43282
+ ) })
43041
43283
  ] })
43042
43284
  ]
43043
43285
  }
@@ -43045,6 +43287,33 @@ const MentionSlashView = () => {
43045
43287
  }
43046
43288
  );
43047
43289
  };
43290
+ function GroupTab({
43291
+ groupId,
43292
+ label,
43293
+ count,
43294
+ selected,
43295
+ onSelect
43296
+ }) {
43297
+ return /* @__PURE__ */ jsxs(
43298
+ "button",
43299
+ {
43300
+ type: "button",
43301
+ "aria-pressed": selected,
43302
+ "data-mention-group": groupId,
43303
+ "data-testid": `mention-slash-tab-${label}`,
43304
+ title: label,
43305
+ className: `relative shrink-0 scroll-mx-8 px-2 py-1.5 text-sm whitespace-nowrap flex items-center gap-1 ${selected ? "text-foreground font-semibold" : "text-subtlest"}`,
43306
+ onMouseDown: (event) => event.preventDefault(),
43307
+ onClick: onSelect,
43308
+ children: [
43309
+ label,
43310
+ " ",
43311
+ /* @__PURE__ */ jsx("span", { className: "text-subtlest px-1.5 rounded-full bg-dark-200 text-xs tabular-nums shrink-0", children: count }),
43312
+ selected ? /* @__PURE__ */ jsx("span", { className: "absolute inset-x-2 bottom-0 h-0.5 rounded-sm bg-foreground" }) : null
43313
+ ]
43314
+ }
43315
+ );
43316
+ }
43048
43317
  function groupRows(rows) {
43049
43318
  const groups = [];
43050
43319
  for (const row of rows) {
@@ -43072,11 +43341,22 @@ function mentionSlashKeydown(ctx) {
43072
43341
  event.preventDefault();
43073
43342
  api.nav("prev");
43074
43343
  return true;
43344
+ case "ArrowRight":
43345
+ event.preventDefault();
43346
+ api.navGroup("next");
43347
+ return true;
43348
+ case "ArrowLeft":
43349
+ event.preventDefault();
43350
+ api.navGroup("prev");
43351
+ return true;
43075
43352
  case "Enter":
43076
- case "Tab":
43077
43353
  event.preventDefault();
43078
43354
  api.pick();
43079
43355
  return true;
43356
+ case "Tab":
43357
+ event.preventDefault();
43358
+ if (!event.shiftKey) api.focusFooterButton();
43359
+ return true;
43080
43360
  case "Escape":
43081
43361
  event.preventDefault();
43082
43362
  api.dismiss();
@@ -70113,7 +70393,7 @@ function legacy(parser) {
70113
70393
  return new LanguageSupport(StreamLanguage.define(parser));
70114
70394
  }
70115
70395
  function sql(dialectName) {
70116
- return import('./index-DnbjsrWF.js').then(m => m.sql({ dialect: m[dialectName] }));
70396
+ return import('./index-hvx6Ru78.js').then(m => m.sql({ dialect: m[dialectName] }));
70117
70397
  }
70118
70398
  /**
70119
70399
  An array of language descriptions for known language packages.
@@ -70124,7 +70404,7 @@ const languages = [
70124
70404
  name: "C",
70125
70405
  extensions: ["c", "h", "ino"],
70126
70406
  load() {
70127
- return import('./index-CsaeJbB5.js').then(m => m.cpp());
70407
+ return import('./index-Byx5Rin8.js').then(m => m.cpp());
70128
70408
  }
70129
70409
  }),
70130
70410
  /*@__PURE__*/LanguageDescription.of({
@@ -70132,7 +70412,7 @@ const languages = [
70132
70412
  alias: ["cpp"],
70133
70413
  extensions: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"],
70134
70414
  load() {
70135
- return import('./index-CsaeJbB5.js').then(m => m.cpp());
70415
+ return import('./index-Byx5Rin8.js').then(m => m.cpp());
70136
70416
  }
70137
70417
  }),
70138
70418
  /*@__PURE__*/LanguageDescription.of({
@@ -70145,14 +70425,14 @@ const languages = [
70145
70425
  name: "CSS",
70146
70426
  extensions: ["css"],
70147
70427
  load() {
70148
- return import('./index-mEwvGwcX.js').then(m => m.css());
70428
+ return import('./index-D_WC_iU-.js').then(m => m.css());
70149
70429
  }
70150
70430
  }),
70151
70431
  /*@__PURE__*/LanguageDescription.of({
70152
70432
  name: "Go",
70153
70433
  extensions: ["go"],
70154
70434
  load() {
70155
- return import('./index-BQa2bres.js').then(m => m.go());
70435
+ return import('./index-DHS4fqlV.js').then(m => m.go());
70156
70436
  }
70157
70437
  }),
70158
70438
  /*@__PURE__*/LanguageDescription.of({
@@ -70160,14 +70440,14 @@ const languages = [
70160
70440
  alias: ["xhtml"],
70161
70441
  extensions: ["html", "htm", "handlebars", "hbs"],
70162
70442
  load() {
70163
- return import('./index-Dk6UNQWp.js').then(m => m.html());
70443
+ return import('./index-wnkG3YUJ.js').then(m => m.html());
70164
70444
  }
70165
70445
  }),
70166
70446
  /*@__PURE__*/LanguageDescription.of({
70167
70447
  name: "Java",
70168
70448
  extensions: ["java"],
70169
70449
  load() {
70170
- return import('./index-BBMUH80b.js').then(m => m.java());
70450
+ return import('./index-CHiJxeZP.js').then(m => m.java());
70171
70451
  }
70172
70452
  }),
70173
70453
  /*@__PURE__*/LanguageDescription.of({
@@ -70175,14 +70455,14 @@ const languages = [
70175
70455
  alias: ["ecmascript", "js", "node"],
70176
70456
  extensions: ["js", "mjs", "cjs"],
70177
70457
  load() {
70178
- return import('./index-BIHNHMyg.js').then(m => m.javascript());
70458
+ return import('./index-xzCgWTs0.js').then(m => m.javascript());
70179
70459
  }
70180
70460
  }),
70181
70461
  /*@__PURE__*/LanguageDescription.of({
70182
70462
  name: "Jinja",
70183
70463
  extensions: ["j2", "jinja", "jinja2"],
70184
70464
  load() {
70185
- return import('./index-paWgasj8.js').then(m => m.jinja());
70465
+ return import('./index-BgpucQu9.js').then(m => m.jinja());
70186
70466
  }
70187
70467
  }),
70188
70468
  /*@__PURE__*/LanguageDescription.of({
@@ -70190,28 +70470,28 @@ const languages = [
70190
70470
  alias: ["json5"],
70191
70471
  extensions: ["json", "map"],
70192
70472
  load() {
70193
- return import('./index-B4R1rT37.js').then(m => m.json());
70473
+ return import('./index-DysiDhtD.js').then(m => m.json());
70194
70474
  }
70195
70475
  }),
70196
70476
  /*@__PURE__*/LanguageDescription.of({
70197
70477
  name: "JSX",
70198
70478
  extensions: ["jsx"],
70199
70479
  load() {
70200
- return import('./index-BIHNHMyg.js').then(m => m.javascript({ jsx: true }));
70480
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ jsx: true }));
70201
70481
  }
70202
70482
  }),
70203
70483
  /*@__PURE__*/LanguageDescription.of({
70204
70484
  name: "LESS",
70205
70485
  extensions: ["less"],
70206
70486
  load() {
70207
- return import('./index-C-bL3Cy9.js').then(m => m.less());
70487
+ return import('./index-DgawIQVL.js').then(m => m.less());
70208
70488
  }
70209
70489
  }),
70210
70490
  /*@__PURE__*/LanguageDescription.of({
70211
70491
  name: "Liquid",
70212
70492
  extensions: ["liquid"],
70213
70493
  load() {
70214
- return import('./index-Dv14TLjz.js').then(m => m.liquid());
70494
+ return import('./index-CZ_tRMOP.js').then(m => m.liquid());
70215
70495
  }
70216
70496
  }),
70217
70497
  /*@__PURE__*/LanguageDescription.of({
@@ -70222,7 +70502,7 @@ const languages = [
70222
70502
  name: "Markdown",
70223
70503
  extensions: ["md", "markdown", "mkd"],
70224
70504
  load() {
70225
- return import('./index-LyNcRvuh.js').then(m => m.markdown());
70505
+ return import('./index-CgxTSc3A.js').then(m => m.markdown());
70226
70506
  }
70227
70507
  }),
70228
70508
  /*@__PURE__*/LanguageDescription.of({
@@ -70237,7 +70517,7 @@ const languages = [
70237
70517
  name: "PHP",
70238
70518
  extensions: ["php", "php3", "php4", "php5", "php7", "phtml"],
70239
70519
  load() {
70240
- return import('./index-DveiglG-.js').then(m => m.php());
70520
+ return import('./index-DC8dl4wM.js').then(m => m.php());
70241
70521
  }
70242
70522
  }),
70243
70523
  /*@__PURE__*/LanguageDescription.of({
@@ -70254,28 +70534,28 @@ const languages = [
70254
70534
  extensions: ["BUILD", "bzl", "py", "pyw"],
70255
70535
  filename: /^(BUCK|BUILD)$/,
70256
70536
  load() {
70257
- return import('./index-DsUx-yKw.js').then(m => m.python());
70537
+ return import('./index-nC_e7r57.js').then(m => m.python());
70258
70538
  }
70259
70539
  }),
70260
70540
  /*@__PURE__*/LanguageDescription.of({
70261
70541
  name: "Rust",
70262
70542
  extensions: ["rs"],
70263
70543
  load() {
70264
- return import('./index-CyTfufcP.js').then(m => m.rust());
70544
+ return import('./index-BCU5wvMA.js').then(m => m.rust());
70265
70545
  }
70266
70546
  }),
70267
70547
  /*@__PURE__*/LanguageDescription.of({
70268
70548
  name: "Sass",
70269
70549
  extensions: ["sass"],
70270
70550
  load() {
70271
- return import('./index-D7noxe1h.js').then(m => m.sass({ indented: true }));
70551
+ return import('./index-ioAG3mIK.js').then(m => m.sass({ indented: true }));
70272
70552
  }
70273
70553
  }),
70274
70554
  /*@__PURE__*/LanguageDescription.of({
70275
70555
  name: "SCSS",
70276
70556
  extensions: ["scss"],
70277
70557
  load() {
70278
- return import('./index-D7noxe1h.js').then(m => m.sass());
70558
+ return import('./index-ioAG3mIK.js').then(m => m.sass());
70279
70559
  }
70280
70560
  }),
70281
70561
  /*@__PURE__*/LanguageDescription.of({
@@ -70291,7 +70571,7 @@ const languages = [
70291
70571
  name: "TSX",
70292
70572
  extensions: ["tsx"],
70293
70573
  load() {
70294
- return import('./index-BIHNHMyg.js').then(m => m.javascript({ jsx: true, typescript: true }));
70574
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ jsx: true, typescript: true }));
70295
70575
  }
70296
70576
  }),
70297
70577
  /*@__PURE__*/LanguageDescription.of({
@@ -70299,14 +70579,14 @@ const languages = [
70299
70579
  alias: ["ts"],
70300
70580
  extensions: ["ts", "mts", "cts"],
70301
70581
  load() {
70302
- return import('./index-BIHNHMyg.js').then(m => m.javascript({ typescript: true }));
70582
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ typescript: true }));
70303
70583
  }
70304
70584
  }),
70305
70585
  /*@__PURE__*/LanguageDescription.of({
70306
70586
  name: "WebAssembly",
70307
70587
  extensions: ["wat", "wast"],
70308
70588
  load() {
70309
- return import('./index-BJKQPlcf.js').then(m => m.wast());
70589
+ return import('./index-BrHQTa5O.js').then(m => m.wast());
70310
70590
  }
70311
70591
  }),
70312
70592
  /*@__PURE__*/LanguageDescription.of({
@@ -70314,7 +70594,7 @@ const languages = [
70314
70594
  alias: ["rss", "wsdl", "xsd"],
70315
70595
  extensions: ["xml", "xsl", "xsd", "svg"],
70316
70596
  load() {
70317
- return import('./index-CFr33LuW.js').then(m => m.xml());
70597
+ return import('./index-wcyxRMSc.js').then(m => m.xml());
70318
70598
  }
70319
70599
  }),
70320
70600
  /*@__PURE__*/LanguageDescription.of({
@@ -70322,7 +70602,7 @@ const languages = [
70322
70602
  alias: ["yml"],
70323
70603
  extensions: ["yaml", "yml"],
70324
70604
  load() {
70325
- return import('./index-DztBKea2.js').then(m => m.yaml());
70605
+ return import('./index-CSYZYQcP.js').then(m => m.yaml());
70326
70606
  }
70327
70607
  }),
70328
70608
  // Legacy modes ported from CodeMirror 5
@@ -71111,13 +71391,13 @@ const languages = [
71111
71391
  name: "Vue",
71112
71392
  extensions: ["vue"],
71113
71393
  load() {
71114
- return import('./index-COD_xliD.js').then(m => m.vue());
71394
+ return import('./index-D3qfXl4a.js').then(m => m.vue());
71115
71395
  }
71116
71396
  }),
71117
71397
  /*@__PURE__*/LanguageDescription.of({
71118
71398
  name: "Angular Template",
71119
71399
  load() {
71120
- return import('./index-DnpXm_wT.js').then(m => m.angular());
71400
+ return import('./index-FrO1JgY0.js').then(m => m.angular());
71121
71401
  }
71122
71402
  })
71123
71403
  ];
@@ -124319,7 +124599,7 @@ function useSlashMenuPortal(container) {
124319
124599
  }
124320
124600
 
124321
124601
  const ReviewSuggestionsViewport = lazy(
124322
- () => import('./index-CgzQ1jj0.js').then((module) => ({ default: module.ReviewSuggestionsViewport }))
124602
+ () => import('./index-QwNEKxue.js').then((module) => ({ default: module.ReviewSuggestionsViewport }))
124323
124603
  );
124324
124604
  const MilkdownEditorInner = ({
124325
124605
  readOnly = false,
@@ -124543,7 +124823,18 @@ const MilkdownEditor = (props) => {
124543
124823
  const mentions = props.mentions ?? [];
124544
124824
  const mentionsRef = useRef(mentions);
124545
124825
  mentionsRef.current = mentions;
124546
- const mentionsRuntime = useMemo(() => ({ providersRef: mentionsRef, providers: mentions }), [mentions]);
124826
+ const onFooterButtonClickRef = useRef(props.footerButton?.onClick);
124827
+ onFooterButtonClickRef.current = props.footerButton?.onClick;
124828
+ const footerButtonLabel = props.footerButton?.label;
124829
+ const mentionsRuntime = useMemo(
124830
+ () => ({
124831
+ providersRef: mentionsRef,
124832
+ providers: mentions,
124833
+ onFooterButtonClickRef,
124834
+ footerButtonLabel
124835
+ }),
124836
+ [mentions, footerButtonLabel]
124837
+ );
124547
124838
  return /* @__PURE__ */ jsx(
124548
124839
  VariableContentChannelsContext.Provider,
124549
124840
  {
@@ -124652,7 +124943,8 @@ const MarkdownSourceEditor = React.forwardRef(
124652
124943
  onChange,
124653
124944
  slashMenu = "basic",
124654
124945
  toolbar = "basic",
124655
- mentions
124946
+ mentions,
124947
+ footerButton
124656
124948
  }, ref) {
124657
124949
  const [mode, setMode] = React.useState("markdown");
124658
124950
  const [markdown, setMarkdown] = React.useState(initialMarkdown);
@@ -124720,6 +125012,7 @@ const MarkdownSourceEditor = React.forwardRef(
124720
125012
  toolbar,
124721
125013
  placeholder,
124722
125014
  mentions,
125015
+ footerButton,
124723
125016
  onContentChange: handleEditorChange
124724
125017
  },
124725
125018
  editorKey