10 Commits

Author SHA1 Message Date
Steve Lau
42e41d2890 release notes 2025-12-24 16:08:18 +08:00
Steve Lau
bc20635e00 feat: support app search even if Spotlight is disabled
Previously, we relied on Spotlight (mdfind) to fetch the app list,
which means it won't work if users disable their Spotlight index.

This commit bumps the applications-rs library, which can now list
apps using `lsregister`, macOS's launch service tool. (See commit [1]
for details). With this, our app search works even tough Spotlight
is disabled.

[1]: ec174b7761
2025-12-24 16:01:55 +08:00
BiggerRain
03af1d46c5 fix: skip window resize when UI size is missing (#1023)
* fix: skip window resize when UI size is missing

* chore: padding

* chore: update

* refactor: update

* chore: height

* chore: height

* chore: defalut value

---------

Co-authored-by: ayang <473033518@qq.com>
2025-12-23 22:02:19 +08:00
SteveLauC
8638724e68 chore: remove file foo (#1026)
It was a placeholder that I added in PR #1009, I forgot to remove it
before merging that PR. Let's remove it now.
2025-12-22 16:12:14 +08:00
ayangweb
6ae2ed0832 fix: esc key fails to close the popover (#1024)
* fix: esc key fails to close the popover

* refactor: update
2025-12-22 11:51:04 +08:00
Hardy
81dab997a9 chore: update release notes for publish 0.10.0-2619 (#1021)
* chore: update release notes for publish 0.10.0-2619

* Add section headers to release notes

Added section headers for breaking changes, features, bug fixes, and improvements.

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: BiggerRain <15911122312@163.COM>
2025-12-22 09:51:59 +08:00
BiggerRain
7a4364665e chore: bump version to 0.10.0 (#1022) 2025-12-19 17:56:32 +08:00
BiggerRain
444ba968c4 chore: hide selection settings (#1020) 2025-12-19 16:15:03 +08:00
ayangweb
206d8db4f4 refactor: disable input auto-correction (#1019) 2025-12-19 15:46:53 +08:00
BiggerRain
7e40632c29 style: adjust delete button color (#1018) 2025-12-19 12:59:58 +08:00
24 changed files with 177 additions and 175 deletions

View File

@@ -10,6 +10,7 @@
"dataurl",
"deeplink",
"deepthink",
"Detch",
"dtolnay",
"dyld",
"elif",
@@ -56,6 +57,7 @@
"rgba",
"rustup",
"screenshotable",
"seprate",
"serde",
"Shadcn",
"swatinem",

View File

@@ -7,7 +7,19 @@ title: "Release Notes"
Information about release notes of Coco App is provided here.
## Latest (In development)
## Latest (In development)
### ❌ Breaking changes
### 🚀 Features
- feat: support app search even if Spotlight is disabled #1028
### 🐛 Bug fix
### ✈️ Improvements
## 0.10.0 (2025-12-19)
### ❌ Breaking changes

0
foo
View File

View File

@@ -1,7 +1,7 @@
{
"name": "coco",
"private": true,
"version": "0.9.1",
"version": "0.10.0",
"type": "module",
"scripts": {
"dev": "vite",

4
src-tauri/Cargo.lock generated
View File

@@ -332,7 +332,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "applications"
version = "0.3.1"
source = "git+https://github.com/infinilabs/applications-rs?rev=b5fac4034a40d42e72f727f1aa1cc1f19fe86653#b5fac4034a40d42e72f727f1aa1cc1f19fe86653"
source = "git+https://github.com/infinilabs/applications-rs?rev=ec174b7761bfa5eb7af0a93218b014e2d1505643#ec174b7761bfa5eb7af0a93218b014e2d1505643"
dependencies = [
"anyhow",
"core-foundation 0.9.4",
@@ -1132,7 +1132,7 @@ dependencies = [
[[package]]
name = "coco"
version = "0.9.1"
version = "0.10.0"
dependencies = [
"actix-files",
"actix-web",

View File

@@ -1,6 +1,6 @@
[package]
name = "coco"
version = "0.9.1"
version = "0.10.0"
description = "Search, connect, collaborate all in one place."
authors = ["INFINI Labs"]
edition = "2024"
@@ -62,7 +62,7 @@ tauri-plugin-drag = "2"
tauri-plugin-macos-permissions = "2"
tauri-plugin-fs-pro = "2"
tauri-plugin-screenshots = "2"
applications = { git = "https://github.com/infinilabs/applications-rs", rev = "b5fac4034a40d42e72f727f1aa1cc1f19fe86653" }
applications = { git = "https://github.com/infinilabs/applications-rs", rev = "ec174b7761bfa5eb7af0a93218b014e2d1505643" }
tokio-native-tls = "0.3" # For wss connections
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }

View File

@@ -156,13 +156,13 @@ pub struct Extension {
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub(crate) struct ViewExtensionUISettings {
/// Show the search bar
#[serde_inline_default(true)]
#[serde_inline_default(false)]
search_bar: bool,
/// Show the filter bar
#[serde_inline_default(true)]
#[serde_inline_default(false)]
filter_bar: bool,
/// Show the footer
#[serde_inline_default(true)]
#[serde_inline_default(false)]
footer: bool,
/// The recommended width of the window for this extension
width: Option<u32>,

View File

@@ -29,7 +29,6 @@ use tauri_plugin_autostart::MacosLauncher;
/// Tauri store name
pub(crate) const COCO_TAURI_STORE: &str = "coco_tauri_store";
pub(crate) const WINDOW_CENTER_BASELINE_HEIGHT: i32 = 590;
lazy_static! {
static ref PREVIOUS_MONITOR_NAME: Mutex<Option<String>> = Mutex::new(None);
@@ -44,37 +43,6 @@ lazy_static! {
/// you access it.
pub(crate) static GLOBAL_TAURI_APP_HANDLE: OnceLock<AppHandle> = OnceLock::new();
#[tauri::command]
async fn change_window_height(handle: AppHandle, height: u32) {
let window: WebviewWindow = handle.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
let mut size = window.outer_size().unwrap();
size.height = height;
window.set_size(size).unwrap();
// Center the window horizontally and vertically based on the baseline height of 590
let monitor = window.primary_monitor().ok().flatten().or_else(|| {
window
.available_monitors()
.ok()
.and_then(|ms| ms.into_iter().next())
});
if let Some(monitor) = monitor {
let monitor_position = monitor.position();
let monitor_size = monitor.size();
let outer_size = window.outer_size().unwrap();
let window_width = outer_size.width as i32;
let x = monitor_position.x + (monitor_size.width as i32 - window_width) / 2;
let y =
monitor_position.y + (monitor_size.height as i32 - WINDOW_CENTER_BASELINE_HEIGHT) / 2;
let _ = window.set_position(PhysicalPosition::new(x, y));
}
}
// Removed unused Payload to avoid unnecessary serde derive macro invocations
#[cfg_attr(mobile, tauri::mobile_entry_point)]
@@ -123,7 +91,6 @@ pub fn run() {
let app = app_builder
.invoke_handler(tauri::generate_handler![
change_window_height,
shortcut::change_shortcut,
shortcut::unregister_shortcut,
shortcut::get_current_shortcut,
@@ -380,12 +347,13 @@ fn move_window_to_active_monitor(window: &WebviewWindow) {
return;
}
};
let window_width = window_size.width as i32;
let window_height = 590 * scale_factor as i32;
// Horizontal center uses actual width, vertical center uses 590 baseline
let window_x = monitor_position.x + (monitor_size.width as i32 - window_width) / 2;
let window_y = monitor_position.y
+ (monitor_size.height as i32 - WINDOW_CENTER_BASELINE_HEIGHT) / 2;
let window_y = monitor_position.y + (monitor_size.height as i32 - window_height) / 2;
if let Err(e) = window.set_position(PhysicalPosition::new(window_x, window_y)) {
log::error!("Failed to move window: {}", e);

View File

@@ -15,12 +15,12 @@ import { useConnectStore } from "@/stores/connectStore";
import FontIcon from "@/components/Common/Icons/FontIcon";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import NoDataImage from "@/components/Common/NoDataImage";
import PopoverInput from "@/components/Common/PopoverInput";
import { AssistantFetcher } from "./AssistantFetcher";
import AssistantItem from "./AssistantItem";
import Pagination from "@/components/Common/Pagination";
import { useSearchStore } from "@/stores/searchStore";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
interface AssistantListProps {
assistantIDs?: string[];
@@ -241,9 +241,10 @@ export function AssistantList({ assistantIDs = [] }: AssistantListProps) {
searchInputRef.current?.focus();
}}
>
<PopoverInput
<Input
ref={searchInputRef}
autoFocus
autoCorrect="off"
value={keyword}
placeholder={t("assistant.popover.search")}
className="w-full h-8"

View File

@@ -63,6 +63,7 @@ export function Connect({ setIsConnect, onAddServer }: ConnectServiceProps) {
type="text"
id="endpoint"
value={endpointLink}
autoCorrect="off"
placeholder={t("cloud.connect.serverPlaceholder")}
onChange={onChangeEndpoint}
className="text-[#101010] dark:text-white flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-800"

View File

@@ -1,36 +0,0 @@
import type { InputProps } from "@/components/ui/input";
import { Input } from "@/components/ui/input";
import { useKeyPress } from "ahooks";
import { forwardRef, useImperativeHandle, useRef } from "react";
import { POPOVER_PANEL_SELECTOR } from "@/constants";
const PopoverInput = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => inputRef.current!);
useKeyPress(
"esc",
(event) => {
if (inputRef.current === document.activeElement) {
event.preventDefault();
event.stopPropagation();
inputRef.current?.blur();
const parentPanel = inputRef.current?.closest(POPOVER_PANEL_SELECTOR);
if (parentPanel instanceof HTMLElement) {
parentPanel.focus();
}
}
},
{
target: inputRef,
}
);
return <Input autoCorrect="off" ref={inputRef} {...(props as any)} />;
});
export default PopoverInput;

View File

@@ -1,9 +1,11 @@
import { FC, HTMLAttributes, useEffect, useRef, useState } from "react";
import { useKeyPress } from "ahooks";
import clsx from "clsx";
import { last } from "lodash-es";
import { POPOVER_PANEL_SELECTOR } from "@/constants";
import {
OPENED_POPOVER_TRIGGER_SELECTOR,
POPOVER_PANEL_SELECTOR,
} from "@/constants";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import { useAppStore } from "@/stores/appStore";
import { KeyType } from "ahooks/lib/useKeyPress";
@@ -43,22 +45,21 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
const [visibleShortcut, setVisibleShortcut] = useState<boolean>();
useEffect(() => {
const popoverPanelEls = document.querySelectorAll(POPOVER_PANEL_SELECTOR);
const popoverPanelEl = last(popoverPanelEls);
const popoverPanelEl = document.querySelector(POPOVER_PANEL_SELECTOR);
const openedPopoverTriggerEl = document.querySelector(
OPENED_POPOVER_TRIGGER_SELECTOR
);
if (!openPopover || !popoverPanelEl) {
return setVisibleShortcut(modifierKeyPressed);
}
const popoverButtonEl = document.querySelector(
`[aria-controls="${popoverPanelEl.id}"]`
const isChildInPanel = popoverPanelEl?.contains(childrenRef.current);
const isChildInTrigger = openedPopoverTriggerEl?.contains(
childrenRef.current
);
const isChildInPanel = popoverPanelEl?.contains(childrenRef.current);
const isChildInButton = popoverButtonEl?.contains(childrenRef.current);
const isChildInPopover = isChildInPanel || isChildInButton;
const isChildInPopover = isChildInPanel || isChildInTrigger;
setVisibleShortcut(isChildInPopover && modifierKeyPressed);
}, [openPopover, modifierKeyPressed]);
@@ -111,7 +112,7 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
{showTooltip && visibleShortcut ? (
<div
className={clsx(
"size-4 flex items-center justify-center font-normal text-xs text-[#333] leading-[14px] bg-[#ccc] dark:bg-[#6B6B6B] rounded-md shadow-[-6px_0px_6px_2px_#fff] dark:shadow-[-6px_0px_6px_2px_#000] absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2",
"size-4 flex items-center justify-center font-normal text-xs text-[#333] leading-3.5 bg-[#ccc] dark:bg-[#6B6B6B] rounded-md shadow-[-6px_0px_6px_2px_#fff] dark:shadow-[-6px_0px_6px_2px_#000] absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2",
shortcutClassName
)}
>

View File

@@ -243,7 +243,7 @@ const ExtensionDetail: FC<ExtensionDetailProps> = (props) => {
}}
deleteButtonProps={{
className:
"!text-[#FF4949] bg-[#F8F9FA] dark:text-white dark:bg-[#202126] border-[#E6E6E6] dark:border-white/10",
"text-white bg-[#FF4949] hover:bg-[#FF4949] border-[#E6E6E6] dark:border-white/10",
}}
setIsOpen={setIsOpen}
onCancel={handleCancel}

View File

@@ -17,10 +17,10 @@ import Checkbox from "@/components/Common/Checkbox";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import VisibleKey from "@/components/Common/VisibleKey";
import NoDataImage from "@/components/Common/NoDataImage";
import PopoverInput from "@/components/Common/PopoverInput";
import Pagination from "@/components/Common/Pagination";
import { SearchQuery } from "@/utils";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
interface MCPPopoverProps {
mcp_servers: any;
@@ -263,8 +263,9 @@ export default function MCPPopover({
/>
</div>
<PopoverInput
<Input
autoFocus
autoCorrect="off"
value={keyword}
ref={searchInputRef}
className="size-full px-2 rounded-lg border dark:border-white/10 bg-transparent"

View File

@@ -17,9 +17,9 @@ import Checkbox from "@/components/Common/Checkbox";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import VisibleKey from "@/components/Common/VisibleKey";
import NoDataImage from "@/components/Common/NoDataImage";
import PopoverInput from "@/components/Common/PopoverInput";
import Pagination from "@/components/Common/Pagination";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
interface SearchPopoverProps {
datasource: any;
@@ -271,8 +271,9 @@ export default function SearchPopover({
/>
</div>
<PopoverInput
<Input
autoFocus
autoCorrect="off"
value={keyword}
ref={searchInputRef}
className="size-full px-2 rounded-lg border dark:border-white/10 bg-transparent"

View File

@@ -7,7 +7,7 @@ import { useSearchStore } from "@/stores/searchStore";
import {
ExtensionFileSystemPermission,
FileSystemAccess,
ViewExtensionUISettings,
ViewExtensionUISettingsOrNull,
} from "../Settings/Extensions";
import platformAdapter from "@/utils/platformAdapter";
import { useShortcutsStore } from "@/stores/shortcutsStore";
@@ -18,7 +18,7 @@ const ViewExtension: React.FC = () => {
const { viewExtensionOpened } = useSearchStore();
const isTauri = useAppStore((state) => state.isTauri);
// Complete list of the backend APIs, grouped by their category.
const [apis, setApis] = useState<Map<string, string[]> | null>(null);
const { setModifierKeyPressed } = useShortcutsStore();
@@ -39,9 +39,14 @@ const ViewExtension: React.FC = () => {
y: number;
} | null>(null);
const iframeRef = useRef<HTMLIFrameElement | null>(null);
const DEFAULT_VIEW_WIDTH = 1200;
const DEFAULT_VIEW_HEIGHT = 900;
const [scale, setScale] = useState(1);
const [fallbackViewSize, setFallbackViewSize] = useState<{
width: number;
height: number;
} | null>(() => {
if (typeof window === "undefined") return null;
return { width: window.innerWidth, height: window.innerHeight };
});
if (viewExtensionOpened == null) {
// When this view gets loaded, this state should not be NULL.
@@ -191,23 +196,38 @@ const ViewExtension: React.FC = () => {
}, [reversedApis, permission]); // Add apiPermissions as dependency
const fileUrl = viewExtensionOpened[2];
const ui: ViewExtensionUISettings | undefined = useMemo(() => {
return viewExtensionOpened[4] as ViewExtensionUISettings | undefined;
const ui: ViewExtensionUISettingsOrNull = useMemo(() => {
return viewExtensionOpened[4] as ViewExtensionUISettingsOrNull;
}, [viewExtensionOpened]);
const resizable = ui?.resizable;
const uiWidth = ui && typeof ui.width === "number" ? ui.width : null;
const uiHeight = ui && typeof ui.height === "number" ? ui.height : null;
const hasExplicitWindowSize = uiWidth != null && uiHeight != null;
const baseWidth = useMemo(() => {
return ui && typeof ui?.width === "number" ? ui.width : DEFAULT_VIEW_WIDTH;
}, [ui]);
if (uiWidth != null) return uiWidth;
if (fallbackViewSize != null) return fallbackViewSize.width;
return 0;
}, [uiWidth, fallbackViewSize]);
const baseHeight = useMemo(() => {
return ui && typeof ui?.height === "number" ? ui.height : DEFAULT_VIEW_HEIGHT;
}, [ui]);
if (uiHeight != null) return uiHeight;
if (fallbackViewSize != null) return fallbackViewSize.height;
return 0;
}, [uiHeight, fallbackViewSize]);
const recomputeScale = useCallback(async () => {
if (!hasExplicitWindowSize) {
setScale(1);
return;
}
const size = await platformAdapter.getWindowSize();
const nextScale = Math.min(size.width / baseWidth, size.height / baseHeight);
const nextScale = Math.min(
size.width / baseWidth,
size.height / baseHeight
);
setScale(Math.max(nextScale, 0.1));
}, [baseWidth, baseHeight]);
}, [hasExplicitWindowSize, baseWidth, baseHeight]);
const applyFullscreen = useCallback(
async (next: boolean) => {
@@ -247,16 +267,23 @@ const ViewExtension: React.FC = () => {
if (!isMac) {
await platformAdapter.setWindowFullscreen(false);
}
const nextWidth =
ui && typeof ui.width === "number" ? ui.width : DEFAULT_VIEW_WIDTH;
const nextHeight =
ui && typeof ui.height === "number" ? ui.height : DEFAULT_VIEW_HEIGHT;
const nextResizable =
ui && typeof ui.resizable === "boolean" ? ui.resizable : true;
await platformAdapter.setWindowSize(nextWidth, nextHeight);
await platformAdapter.setWindowResizable(nextResizable);
await platformAdapter.centerOnCurrentMonitor();
await recomputeScale();
if (fullscreenPrevRef.current) {
const prev = fullscreenPrevRef.current;
await platformAdapter.setWindowSize(prev.width, prev.height);
await platformAdapter.setWindowResizable(prev.resizable);
await platformAdapter.setWindowPosition(prev.x, prev.y);
fullscreenPrevRef.current = null;
await recomputeScale();
} else if (hasExplicitWindowSize) {
const nextResizable =
ui && typeof ui.resizable === "boolean" ? ui.resizable : true;
await platformAdapter.setWindowSize(uiWidth, uiHeight);
await platformAdapter.setWindowResizable(nextResizable);
await platformAdapter.centerOnCurrentMonitor();
await recomputeScale();
} else {
await recomputeScale();
}
setTimeout(() => {
iframeRef.current?.focus();
try {
@@ -274,6 +301,7 @@ const ViewExtension: React.FC = () => {
const size = await platformAdapter.getWindowSize();
const resizable = await platformAdapter.isWindowResizable();
const pos = await platformAdapter.getWindowPosition();
setFallbackViewSize({ width: size.width, height: size.height });
prevWindowRef.current = {
width: size.width,
height: size.height,
@@ -282,17 +310,16 @@ const ViewExtension: React.FC = () => {
y: pos.y,
};
const nextWidth =
ui && typeof ui.width === "number" ? ui.width : DEFAULT_VIEW_WIDTH;
const nextHeight =
ui && typeof ui.height === "number" ? ui.height : DEFAULT_VIEW_HEIGHT;
const nextResizable =
ui && typeof ui.resizable === "boolean" ? ui.resizable : true;
await platformAdapter.setWindowSize(nextWidth, nextHeight);
await platformAdapter.setWindowResizable(nextResizable);
await platformAdapter.centerOnCurrentMonitor();
await recomputeScale();
if (hasExplicitWindowSize) {
const nextResizable =
ui && typeof ui.resizable === "boolean" ? ui.resizable : true;
await platformAdapter.setWindowSize(uiWidth, uiHeight);
await platformAdapter.setWindowResizable(nextResizable);
await platformAdapter.centerOnCurrentMonitor();
await recomputeScale();
} else {
await recomputeScale();
}
setTimeout(() => {
iframeRef.current?.focus();
try {
@@ -324,7 +351,14 @@ const ViewExtension: React.FC = () => {
prevWindowRef.current = null;
}
};
}, [viewExtensionOpened]);
}, [
viewExtensionOpened,
ui,
hasExplicitWindowSize,
uiWidth,
uiHeight,
recomputeScale,
]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape" && isFullscreen) {
@@ -342,7 +376,6 @@ const ViewExtension: React.FC = () => {
return (
<div className="relative w-full h-full">
{isFullscreen && <div className="absolute inset-0 pointer-events-none" />}
{resizable && (
<button
aria-label={
@@ -371,18 +404,20 @@ const ViewExtension: React.FC = () => {
</button>
)}
{/* Focus helper button */}
<button
aria-label={t("viewExtension.focus")}
className="absolute top-2 right-12 z-10 rounded-md bg-black/40 text-white p-2 hover:bg-black/60 focus:outline-none"
onClick={() => {
iframeRef.current?.focus();
try {
iframeRef.current?.contentWindow?.focus();
} catch {}
}}
>
<Focus className="size-4"/>
</button>
{resizable && (
<button
aria-label={t("viewExtension.focus")}
className="absolute top-2 right-12 z-10 rounded-md bg-black/40 text-white p-2 hover:bg-black/60 focus:outline-none"
onClick={() => {
iframeRef.current?.focus();
try {
iframeRef.current?.contentWindow?.focus();
} catch {}
}}
>
<Focus className="size-4" />
</button>
)}
<div
className="w-full h-full flex items-center justify-center"
onMouseDownCapture={() => {
@@ -398,10 +433,8 @@ const ViewExtension: React.FC = () => {
<iframe
ref={iframeRef}
src={fileUrl}
className="border-0"
className="border-0 w-full h-full"
style={{
width: `${baseWidth}px`,
height: `${baseHeight}px`,
transform: `scale(${scale})`,
transformOrigin: "center center",
outline: "none",

View File

@@ -182,12 +182,9 @@ function SearchChat({
});
useEffect(() => {
const unlisten = platformAdapter.listenEvent(
"refresh-window-size",
() => {
debouncedSetWindowSize();
}
);
const unlisten = platformAdapter.listenEvent("refresh-window-size", () => {
debouncedSetWindowSize();
});
return () => {
unlisten
.then((fn) => {

View File

@@ -21,8 +21,8 @@ import SettingsInput from "@/components//Settings/SettingsInput";
import platformAdapter from "@/utils/platformAdapter";
import UpdateSettings from "./components/UpdateSettings";
import SettingsToggle from "../SettingsToggle";
import SelectionSettings from "./components/Selection";
import { isMac } from "@/utils/platform";
// import SelectionSettings from "./components/Selection";
// import { isMac } from "@/utils/platform";
import {
Select,
SelectTrigger,
@@ -196,7 +196,7 @@ const Advanced = () => {
})}
</div>
{isMac && <SelectionSettings />}
{/* {isMac && <SelectionSettings />} */}
<Shortcuts />

View File

@@ -81,6 +81,8 @@ export interface ViewExtensionUISettings {
detachable: boolean;
}
export type ViewExtensionUISettingsOrNull = ViewExtensionUISettings | null | undefined;
export interface Extension {
id: ExtensionId;
type: ExtensionType;

View File

@@ -1,6 +1,7 @@
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "@/lib/utils";
import { OPENED_POPOVER_TRIGGER_SELECTOR } from "@/constants";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
@@ -34,6 +35,24 @@ const PopoverContent = React.forwardRef<
)}
data-popover-panel
id={panelId}
onEscapeKeyDown={(event) => {
event.stopPropagation();
event.preventDefault();
if (
document.activeElement instanceof HTMLInputElement ||
document.activeElement instanceof HTMLTextAreaElement
) {
return document.activeElement.blur();
}
const el = document.querySelector(OPENED_POPOVER_TRIGGER_SELECTOR);
if (el instanceof HTMLElement) {
el.click();
}
}}
{...props}
/>
)

View File

@@ -1,8 +1,11 @@
export const POPOVER_PANEL_SELECTOR = '[data-popover-panel]';
export const POPOVER_PANEL_SELECTOR = "[data-radix-popper-content-wrapper]";
export const HISTORY_PANEL_ID = "headlessui-popover-panel:history-panel";
export const OPENED_POPOVER_TRIGGER_SELECTOR =
"[aria-haspopup='dialog'][aria-expanded='true'][data-state='open']";
export const CONTEXT_MENU_PANEL_ID = "headlessui-popover-panel:context-menu";
export const HISTORY_PANEL_ID = "popover-panel:history-panel";
export const CONTEXT_MENU_PANEL_ID = "popover-panel:context-menu";
export const DEFAULT_COCO_SERVER_ID = "default_coco_server";

View File

@@ -5,20 +5,15 @@ import { HISTORY_PANEL_ID } from "@/constants";
import { closeHistoryPanel } from "@/utils";
const useEscape = () => {
const visibleContextMenu = useSearchStore((state) => {
return state.visibleContextMenu;
});
const setVisibleContextMenu = useSearchStore((state) => {
return state.setVisibleContextMenu;
});
const viewExtensionOpened = useSearchStore((state) => {
return state.viewExtensionOpened;
});
const { setVisibleContextMenu } = useSearchStore();
useKeyPress("esc", (event) => {
event.preventDefault();
event.stopPropagation();
const { visibleContextMenu, viewExtensionOpened } =
useSearchStore.getState();
if (
document.activeElement instanceof HTMLInputElement ||
document.activeElement instanceof HTMLTextAreaElement
@@ -39,6 +34,7 @@ const useEscape = () => {
if (viewExtensionOpened != null) {
return;
}
platformAdapter.hideWindow();
});
};

View File

@@ -16,8 +16,9 @@ export const useModifierKeyPress = () => {
useKeyPress(
modifierKey,
(event) => {
const popoverPanelEl = document.querySelector(POPOVER_PANEL_SELECTOR);
setOpenPopover(Boolean(popoverPanelEl));
const el = document.querySelector(POPOVER_PANEL_SELECTOR);
setOpenPopover(Boolean(el));
setModifierKeyPressed(event.type === "keydown");
},

View File

@@ -303,7 +303,7 @@ export const visibleSearchBar = () => {
const ui = viewExtensionOpened[4];
return ui?.search_bar ?? true;
return ui?.search_bar ?? false;
};
export const visibleFilterBar = () => {
@@ -316,7 +316,7 @@ export const visibleFilterBar = () => {
const ui = viewExtensionOpened[4];
return ui?.filter_bar ?? true;
return ui?.filter_bar ?? false;
};
export const visibleFooterBar = () => {
@@ -326,7 +326,7 @@ export const visibleFooterBar = () => {
const ui = viewExtensionOpened[4];
return ui?.footer ?? true;
return ui?.footer ?? false;
};
export const installExtensionError = (error: any) => {