@brainfish-ai/editor 0.16.1 → 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 (40) hide show
  1. package/dist/editor/internal/codeMirrorTheme.d.ts +14 -0
  2. package/dist/{index-FnbDXzus.js → index-B7G61KeU.js} +1 -1
  3. package/dist/{index-D1lvHOEq.js → index-BCU5wvMA.js} +2 -2
  4. package/dist/{index-D2xHwKn1.js → index-BgpucQu9.js} +3 -3
  5. package/dist/{index-B3Tj0aeA.js → index-BrHQTa5O.js} +2 -2
  6. package/dist/{index-DLaMyc-O.js → index-Byx5Rin8.js} +2 -2
  7. package/dist/{index-DaEJooLf.js → index-CHiJxeZP.js} +2 -2
  8. package/dist/{index-DQl-jPCB.js → index-CSYZYQcP.js} +2 -2
  9. package/dist/{index-yGP3q8Ph.js → index-CZ_tRMOP.js} +3 -3
  10. package/dist/{index-ugK_d0Eb.js → index-CgxTSc3A.js} +2 -2
  11. package/dist/{index-DcHkonsK.js → index-D3qfXl4a.js} +4 -4
  12. package/dist/{index-3kIhnnQF.js → index-DC8dl4wM.js} +3 -3
  13. package/dist/{index-BoGCS5K8.js → index-DHS4fqlV.js} +2 -2
  14. package/dist/{index-TzlF4I2U.js → index-D_WC_iU-.js} +2 -2
  15. package/dist/{index-DmshtaDi.js → index-DgawIQVL.js} +3 -3
  16. package/dist/{index-Pbdt_JAa.js → index-DysiDhtD.js} +2 -2
  17. package/dist/{index-DC7kmwxC.js → index-FrO1JgY0.js} +4 -4
  18. package/dist/{index-BgzDJCPK.js → index-QwNEKxue.js} +2 -2
  19. package/dist/{index-o1kUBM0B.js → index-f6Jh9zCn.js} +494 -163
  20. package/dist/{index-DPERyOhC.js → index-hvx6Ru78.js} +2 -2
  21. package/dist/{index-DnIbufdg.js → index-ioAG3mIK.js} +3 -3
  22. package/dist/{index-dd3JkZcJ.js → index-nC_e7r57.js} +2 -2
  23. package/dist/{index-mjlRw27L.js → index-wcyxRMSc.js} +2 -2
  24. package/dist/{index-DO4yrIc-.js → index-wnkG3YUJ.js} +4 -4
  25. package/dist/{index-CkC8SVWG.js → index-xzCgWTs0.js} +2 -2
  26. package/dist/index.js +1 -1
  27. package/dist/markdown-source-editor/MarkdownSourceEditor.d.ts +2 -0
  28. package/dist/plugins/mentions/core/types.d.ts +2 -0
  29. package/dist/plugins/mentions/integration/slash-factory.d.ts +5 -0
  30. package/dist/plugins/mentions/integration/slash-keydown.d.ts +1 -0
  31. package/dist/plugins/mentions/ui/MentionSlashView.d.ts +1 -0
  32. package/dist/plugins/mentions/ui/filterMentionSlashRows.d.ts +16 -0
  33. package/dist/plugins/mentions/ui/loadMentionSlashMenu.d.ts +9 -0
  34. package/dist/plugins/mentions/ui/mentionSlashMenuState.d.ts +57 -0
  35. package/dist/plugins/mentions/ui/runtime.d.ts +5 -0
  36. package/dist/plugins/mentions/ui/useMentionSlashMenu.d.ts +8 -11
  37. package/dist/stories/mentionBreakFixtures.d.ts +11 -0
  38. package/dist/stories/storybook-utils.d.ts +4 -0
  39. package/dist/types.d.ts +8 -0
  40. 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();
@@ -43135,7 +43415,11 @@ const getThemeFromHtml = () => {
43135
43415
  return getSystemTheme();
43136
43416
  };
43137
43417
  const useEditorTheme = (theme = "system") => {
43138
- const [resolvedTheme, setResolvedTheme] = useState(theme === "system" ? "light" : theme);
43418
+ const [resolvedTheme, setResolvedTheme] = useState(() => {
43419
+ if (theme !== "system") return theme;
43420
+ if (typeof document === "undefined") return "light";
43421
+ return getThemeFromHtml();
43422
+ });
43139
43423
  useEffect(() => {
43140
43424
  if (theme !== "system") {
43141
43425
  setResolvedTheme(theme);
@@ -70109,7 +70393,7 @@ function legacy(parser) {
70109
70393
  return new LanguageSupport(StreamLanguage.define(parser));
70110
70394
  }
70111
70395
  function sql(dialectName) {
70112
- return import('./index-DPERyOhC.js').then(m => m.sql({ dialect: m[dialectName] }));
70396
+ return import('./index-hvx6Ru78.js').then(m => m.sql({ dialect: m[dialectName] }));
70113
70397
  }
70114
70398
  /**
70115
70399
  An array of language descriptions for known language packages.
@@ -70120,7 +70404,7 @@ const languages = [
70120
70404
  name: "C",
70121
70405
  extensions: ["c", "h", "ino"],
70122
70406
  load() {
70123
- return import('./index-DLaMyc-O.js').then(m => m.cpp());
70407
+ return import('./index-Byx5Rin8.js').then(m => m.cpp());
70124
70408
  }
70125
70409
  }),
70126
70410
  /*@__PURE__*/LanguageDescription.of({
@@ -70128,7 +70412,7 @@ const languages = [
70128
70412
  alias: ["cpp"],
70129
70413
  extensions: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"],
70130
70414
  load() {
70131
- return import('./index-DLaMyc-O.js').then(m => m.cpp());
70415
+ return import('./index-Byx5Rin8.js').then(m => m.cpp());
70132
70416
  }
70133
70417
  }),
70134
70418
  /*@__PURE__*/LanguageDescription.of({
@@ -70141,14 +70425,14 @@ const languages = [
70141
70425
  name: "CSS",
70142
70426
  extensions: ["css"],
70143
70427
  load() {
70144
- return import('./index-TzlF4I2U.js').then(m => m.css());
70428
+ return import('./index-D_WC_iU-.js').then(m => m.css());
70145
70429
  }
70146
70430
  }),
70147
70431
  /*@__PURE__*/LanguageDescription.of({
70148
70432
  name: "Go",
70149
70433
  extensions: ["go"],
70150
70434
  load() {
70151
- return import('./index-BoGCS5K8.js').then(m => m.go());
70435
+ return import('./index-DHS4fqlV.js').then(m => m.go());
70152
70436
  }
70153
70437
  }),
70154
70438
  /*@__PURE__*/LanguageDescription.of({
@@ -70156,14 +70440,14 @@ const languages = [
70156
70440
  alias: ["xhtml"],
70157
70441
  extensions: ["html", "htm", "handlebars", "hbs"],
70158
70442
  load() {
70159
- return import('./index-DO4yrIc-.js').then(m => m.html());
70443
+ return import('./index-wnkG3YUJ.js').then(m => m.html());
70160
70444
  }
70161
70445
  }),
70162
70446
  /*@__PURE__*/LanguageDescription.of({
70163
70447
  name: "Java",
70164
70448
  extensions: ["java"],
70165
70449
  load() {
70166
- return import('./index-DaEJooLf.js').then(m => m.java());
70450
+ return import('./index-CHiJxeZP.js').then(m => m.java());
70167
70451
  }
70168
70452
  }),
70169
70453
  /*@__PURE__*/LanguageDescription.of({
@@ -70171,14 +70455,14 @@ const languages = [
70171
70455
  alias: ["ecmascript", "js", "node"],
70172
70456
  extensions: ["js", "mjs", "cjs"],
70173
70457
  load() {
70174
- return import('./index-CkC8SVWG.js').then(m => m.javascript());
70458
+ return import('./index-xzCgWTs0.js').then(m => m.javascript());
70175
70459
  }
70176
70460
  }),
70177
70461
  /*@__PURE__*/LanguageDescription.of({
70178
70462
  name: "Jinja",
70179
70463
  extensions: ["j2", "jinja", "jinja2"],
70180
70464
  load() {
70181
- return import('./index-D2xHwKn1.js').then(m => m.jinja());
70465
+ return import('./index-BgpucQu9.js').then(m => m.jinja());
70182
70466
  }
70183
70467
  }),
70184
70468
  /*@__PURE__*/LanguageDescription.of({
@@ -70186,28 +70470,28 @@ const languages = [
70186
70470
  alias: ["json5"],
70187
70471
  extensions: ["json", "map"],
70188
70472
  load() {
70189
- return import('./index-Pbdt_JAa.js').then(m => m.json());
70473
+ return import('./index-DysiDhtD.js').then(m => m.json());
70190
70474
  }
70191
70475
  }),
70192
70476
  /*@__PURE__*/LanguageDescription.of({
70193
70477
  name: "JSX",
70194
70478
  extensions: ["jsx"],
70195
70479
  load() {
70196
- return import('./index-CkC8SVWG.js').then(m => m.javascript({ jsx: true }));
70480
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ jsx: true }));
70197
70481
  }
70198
70482
  }),
70199
70483
  /*@__PURE__*/LanguageDescription.of({
70200
70484
  name: "LESS",
70201
70485
  extensions: ["less"],
70202
70486
  load() {
70203
- return import('./index-DmshtaDi.js').then(m => m.less());
70487
+ return import('./index-DgawIQVL.js').then(m => m.less());
70204
70488
  }
70205
70489
  }),
70206
70490
  /*@__PURE__*/LanguageDescription.of({
70207
70491
  name: "Liquid",
70208
70492
  extensions: ["liquid"],
70209
70493
  load() {
70210
- return import('./index-yGP3q8Ph.js').then(m => m.liquid());
70494
+ return import('./index-CZ_tRMOP.js').then(m => m.liquid());
70211
70495
  }
70212
70496
  }),
70213
70497
  /*@__PURE__*/LanguageDescription.of({
@@ -70218,7 +70502,7 @@ const languages = [
70218
70502
  name: "Markdown",
70219
70503
  extensions: ["md", "markdown", "mkd"],
70220
70504
  load() {
70221
- return import('./index-ugK_d0Eb.js').then(m => m.markdown());
70505
+ return import('./index-CgxTSc3A.js').then(m => m.markdown());
70222
70506
  }
70223
70507
  }),
70224
70508
  /*@__PURE__*/LanguageDescription.of({
@@ -70233,7 +70517,7 @@ const languages = [
70233
70517
  name: "PHP",
70234
70518
  extensions: ["php", "php3", "php4", "php5", "php7", "phtml"],
70235
70519
  load() {
70236
- return import('./index-3kIhnnQF.js').then(m => m.php());
70520
+ return import('./index-DC8dl4wM.js').then(m => m.php());
70237
70521
  }
70238
70522
  }),
70239
70523
  /*@__PURE__*/LanguageDescription.of({
@@ -70250,28 +70534,28 @@ const languages = [
70250
70534
  extensions: ["BUILD", "bzl", "py", "pyw"],
70251
70535
  filename: /^(BUCK|BUILD)$/,
70252
70536
  load() {
70253
- return import('./index-dd3JkZcJ.js').then(m => m.python());
70537
+ return import('./index-nC_e7r57.js').then(m => m.python());
70254
70538
  }
70255
70539
  }),
70256
70540
  /*@__PURE__*/LanguageDescription.of({
70257
70541
  name: "Rust",
70258
70542
  extensions: ["rs"],
70259
70543
  load() {
70260
- return import('./index-D1lvHOEq.js').then(m => m.rust());
70544
+ return import('./index-BCU5wvMA.js').then(m => m.rust());
70261
70545
  }
70262
70546
  }),
70263
70547
  /*@__PURE__*/LanguageDescription.of({
70264
70548
  name: "Sass",
70265
70549
  extensions: ["sass"],
70266
70550
  load() {
70267
- return import('./index-DnIbufdg.js').then(m => m.sass({ indented: true }));
70551
+ return import('./index-ioAG3mIK.js').then(m => m.sass({ indented: true }));
70268
70552
  }
70269
70553
  }),
70270
70554
  /*@__PURE__*/LanguageDescription.of({
70271
70555
  name: "SCSS",
70272
70556
  extensions: ["scss"],
70273
70557
  load() {
70274
- return import('./index-DnIbufdg.js').then(m => m.sass());
70558
+ return import('./index-ioAG3mIK.js').then(m => m.sass());
70275
70559
  }
70276
70560
  }),
70277
70561
  /*@__PURE__*/LanguageDescription.of({
@@ -70287,7 +70571,7 @@ const languages = [
70287
70571
  name: "TSX",
70288
70572
  extensions: ["tsx"],
70289
70573
  load() {
70290
- return import('./index-CkC8SVWG.js').then(m => m.javascript({ jsx: true, typescript: true }));
70574
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ jsx: true, typescript: true }));
70291
70575
  }
70292
70576
  }),
70293
70577
  /*@__PURE__*/LanguageDescription.of({
@@ -70295,14 +70579,14 @@ const languages = [
70295
70579
  alias: ["ts"],
70296
70580
  extensions: ["ts", "mts", "cts"],
70297
70581
  load() {
70298
- return import('./index-CkC8SVWG.js').then(m => m.javascript({ typescript: true }));
70582
+ return import('./index-xzCgWTs0.js').then(m => m.javascript({ typescript: true }));
70299
70583
  }
70300
70584
  }),
70301
70585
  /*@__PURE__*/LanguageDescription.of({
70302
70586
  name: "WebAssembly",
70303
70587
  extensions: ["wat", "wast"],
70304
70588
  load() {
70305
- return import('./index-B3Tj0aeA.js').then(m => m.wast());
70589
+ return import('./index-BrHQTa5O.js').then(m => m.wast());
70306
70590
  }
70307
70591
  }),
70308
70592
  /*@__PURE__*/LanguageDescription.of({
@@ -70310,7 +70594,7 @@ const languages = [
70310
70594
  alias: ["rss", "wsdl", "xsd"],
70311
70595
  extensions: ["xml", "xsl", "xsd", "svg"],
70312
70596
  load() {
70313
- return import('./index-mjlRw27L.js').then(m => m.xml());
70597
+ return import('./index-wcyxRMSc.js').then(m => m.xml());
70314
70598
  }
70315
70599
  }),
70316
70600
  /*@__PURE__*/LanguageDescription.of({
@@ -70318,7 +70602,7 @@ const languages = [
70318
70602
  alias: ["yml"],
70319
70603
  extensions: ["yaml", "yml"],
70320
70604
  load() {
70321
- return import('./index-DQl-jPCB.js').then(m => m.yaml());
70605
+ return import('./index-CSYZYQcP.js').then(m => m.yaml());
70322
70606
  }
70323
70607
  }),
70324
70608
  // Legacy modes ported from CodeMirror 5
@@ -71107,13 +71391,13 @@ const languages = [
71107
71391
  name: "Vue",
71108
71392
  extensions: ["vue"],
71109
71393
  load() {
71110
- return import('./index-DcHkonsK.js').then(m => m.vue());
71394
+ return import('./index-D3qfXl4a.js').then(m => m.vue());
71111
71395
  }
71112
71396
  }),
71113
71397
  /*@__PURE__*/LanguageDescription.of({
71114
71398
  name: "Angular Template",
71115
71399
  load() {
71116
- return import('./index-DC7kmwxC.js').then(m => m.angular());
71400
+ return import('./index-FrO1JgY0.js').then(m => m.angular());
71117
71401
  }
71118
71402
  })
71119
71403
  ];
@@ -110760,6 +111044,38 @@ const createVitesseLightTheme = (options = {}) => {
110760
111044
  };
110761
111045
  const vitesseLight = createVitesseLightTheme();
110762
111046
 
111047
+ const themeCompartment = new Compartment();
111048
+ const appliedTheme = /* @__PURE__ */ new WeakMap();
111049
+ const themeExtension = (theme) => theme === "dark" ? oneDark : vitesseLight;
111050
+ const applyTheme = (view, theme) => {
111051
+ if (appliedTheme.get(view) === theme) return;
111052
+ appliedTheme.set(view, theme);
111053
+ view.dispatch({ effects: themeCompartment.reconfigure(themeExtension(theme)) });
111054
+ };
111055
+ const codeMirrorThemeConfig = (themeRef) => ({
111056
+ theme: themeCompartment.of(themeExtension(themeRef.current)),
111057
+ extensions: [
111058
+ ViewPlugin.fromClass(
111059
+ class {
111060
+ constructor(view) {
111061
+ queueMicrotask(() => {
111062
+ if (!view.dom.isConnected) return;
111063
+ applyTheme(view, themeRef.current);
111064
+ });
111065
+ }
111066
+ }
111067
+ )
111068
+ ]
111069
+ });
111070
+ const syncCodeMirrorTheme = (root, theme) => {
111071
+ root.querySelectorAll(".cm-editor").forEach((node) => {
111072
+ if (!(node instanceof HTMLElement)) return;
111073
+ const view = EditorView.findFromDOM(node);
111074
+ if (!view) return;
111075
+ applyTheme(view, theme);
111076
+ });
111077
+ };
111078
+
110763
111079
  var DateType = /* @__PURE__ */ ((DateType2) => {
110764
111080
  DateType2["DATE"] = "date";
110765
111081
  DateType2["TIME"] = "time";
@@ -117237,9 +117553,7 @@ function buildCrepe({
117237
117553
  }
117238
117554
  }
117239
117555
  },
117240
- [Crepe.Feature.CodeMirror]: {
117241
- theme: resolvedThemeRef.current === "dark" ? oneDark : vitesseLight
117242
- },
117556
+ [Crepe.Feature.CodeMirror]: codeMirrorThemeConfig(resolvedThemeRef),
117243
117557
  ...placeholder ? { [Crepe.Feature.Placeholder]: { text: placeholder, mode: "doc" } } : {}
117244
117558
  }
117245
117559
  });
@@ -124285,7 +124599,7 @@ function useSlashMenuPortal(container) {
124285
124599
  }
124286
124600
 
124287
124601
  const ReviewSuggestionsViewport = lazy(
124288
- () => import('./index-BgzDJCPK.js').then((module) => ({ default: module.ReviewSuggestionsViewport }))
124602
+ () => import('./index-QwNEKxue.js').then((module) => ({ default: module.ReviewSuggestionsViewport }))
124289
124603
  );
124290
124604
  const MilkdownEditorInner = ({
124291
124605
  readOnly = false,
@@ -124482,6 +124796,10 @@ const MilkdownEditorInner = ({
124482
124796
  [editorReadyRef]
124483
124797
  );
124484
124798
  useSlashMenuPortal(editorHost);
124799
+ useEffect(() => {
124800
+ if (!editorHost) return;
124801
+ syncCodeMirrorTheme(editorHost, resolvedTheme);
124802
+ }, [editorHost, resolvedTheme]);
124485
124803
  if (!reviewSuggestionsLoader && !hasReviewSuggestions) {
124486
124804
  return /* @__PURE__ */ jsx("div", { ref: containerRef, className, "data-testid": "brainfish-editor", children: /* @__PURE__ */ jsx(Milkdown, {}) });
124487
124805
  }
@@ -124505,7 +124823,18 @@ const MilkdownEditor = (props) => {
124505
124823
  const mentions = props.mentions ?? [];
124506
124824
  const mentionsRef = useRef(mentions);
124507
124825
  mentionsRef.current = mentions;
124508
- 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
+ );
124509
124838
  return /* @__PURE__ */ jsx(
124510
124839
  VariableContentChannelsContext.Provider,
124511
124840
  {
@@ -124614,7 +124943,8 @@ const MarkdownSourceEditor = React.forwardRef(
124614
124943
  onChange,
124615
124944
  slashMenu = "basic",
124616
124945
  toolbar = "basic",
124617
- mentions
124946
+ mentions,
124947
+ footerButton
124618
124948
  }, ref) {
124619
124949
  const [mode, setMode] = React.useState("markdown");
124620
124950
  const [markdown, setMarkdown] = React.useState(initialMarkdown);
@@ -124682,6 +125012,7 @@ const MarkdownSourceEditor = React.forwardRef(
124682
125012
  toolbar,
124683
125013
  placeholder,
124684
125014
  mentions,
125015
+ footerButton,
124685
125016
  onContentChange: handleEditorChange
124686
125017
  },
124687
125018
  editorKey