@agentaily/design-system 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +112 -0
- package/README.md +81 -0
- package/dist/assets/logo/agentaily-mark-black.svg +5 -0
- package/dist/assets/logo/agentaily-mark-white.svg +5 -0
- package/dist/components/ai/Attachments.d.ts +23 -0
- package/dist/components/ai/Attachments.js +96 -0
- package/dist/components/ai/Attachments.js.map +1 -0
- package/dist/components/ai/Checkpoint.d.ts +3 -0
- package/dist/components/ai/Checkpoint.js +38 -0
- package/dist/components/ai/Checkpoint.js.map +1 -0
- package/dist/components/ai/Confirmation.d.ts +3 -0
- package/dist/components/ai/Confirmation.js +54 -0
- package/dist/components/ai/Confirmation.js.map +1 -0
- package/dist/components/ai/Context.d.ts +3 -0
- package/dist/components/ai/Context.js +63 -0
- package/dist/components/ai/Context.js.map +1 -0
- package/dist/components/ai/Conversation.d.ts +3 -0
- package/dist/components/ai/Conversation.js +53 -0
- package/dist/components/ai/Conversation.js.map +1 -0
- package/dist/components/ai/ModelSelector.d.ts +19 -0
- package/dist/components/ai/ModelSelector.js +92 -0
- package/dist/components/ai/ModelSelector.js.map +1 -0
- package/dist/components/ai/Plan.d.ts +4 -0
- package/dist/components/ai/Plan.js +49 -0
- package/dist/components/ai/Plan.js.map +1 -0
- package/dist/components/ai/Queue.d.ts +4 -0
- package/dist/components/ai/Queue.js +45 -0
- package/dist/components/ai/Queue.js.map +1 -0
- package/dist/components/ai/Reasoning.d.ts +17 -0
- package/dist/components/ai/Reasoning.js +60 -0
- package/dist/components/ai/Reasoning.js.map +1 -0
- package/dist/components/ai/Shimmer.d.ts +10 -0
- package/dist/components/ai/Shimmer.js +28 -0
- package/dist/components/ai/Shimmer.js.map +1 -0
- package/dist/components/ai/Sources.d.ts +23 -0
- package/dist/components/ai/Sources.js +65 -0
- package/dist/components/ai/Sources.js.map +1 -0
- package/dist/components/ai/Suggestion.d.ts +19 -0
- package/dist/components/ai/Suggestion.js +40 -0
- package/dist/components/ai/Suggestion.js.map +1 -0
- package/dist/components/ai/Task.d.ts +4 -0
- package/dist/components/ai/Task.js +48 -0
- package/dist/components/ai/Task.js.map +1 -0
- package/dist/components/ai/ToolCall.d.ts +16 -0
- package/dist/components/ai/ToolCall.js +70 -0
- package/dist/components/ai/ToolCall.js.map +1 -0
- package/dist/components/buttons/Button.d.ts +17 -0
- package/dist/components/buttons/Button.js +60 -0
- package/dist/components/buttons/Button.js.map +1 -0
- package/dist/components/buttons/ButtonGroup.d.ts +3 -0
- package/dist/components/buttons/ButtonGroup.js +27 -0
- package/dist/components/buttons/ButtonGroup.js.map +1 -0
- package/dist/components/buttons/IconButton.d.ts +16 -0
- package/dist/components/buttons/IconButton.js +49 -0
- package/dist/components/buttons/IconButton.js.map +1 -0
- package/dist/components/chat/CodeBlock.d.ts +9 -0
- package/dist/components/chat/CodeBlock.js +62 -0
- package/dist/components/chat/CodeBlock.js.map +1 -0
- package/dist/components/chat/Composer.d.ts +17 -0
- package/dist/components/chat/Composer.js +123 -0
- package/dist/components/chat/Composer.js.map +1 -0
- package/dist/components/chat/Message.d.ts +16 -0
- package/dist/components/chat/Message.js +63 -0
- package/dist/components/chat/Message.js.map +1 -0
- package/dist/components/code/Agent.d.ts +3 -0
- package/dist/components/code/Agent.js +44 -0
- package/dist/components/code/Agent.js.map +1 -0
- package/dist/components/code/Artifact.d.ts +3 -0
- package/dist/components/code/Artifact.js +50 -0
- package/dist/components/code/Artifact.js.map +1 -0
- package/dist/components/code/Commit.d.ts +3 -0
- package/dist/components/code/Commit.js +55 -0
- package/dist/components/code/Commit.js.map +1 -0
- package/dist/components/code/EnvironmentVariables.d.ts +4 -0
- package/dist/components/code/EnvironmentVariables.js +49 -0
- package/dist/components/code/EnvironmentVariables.js.map +1 -0
- package/dist/components/code/FileTree.d.ts +4 -0
- package/dist/components/code/FileTree.js +59 -0
- package/dist/components/code/FileTree.js.map +1 -0
- package/dist/components/code/JSXPreview.d.ts +3 -0
- package/dist/components/code/JSXPreview.js +35 -0
- package/dist/components/code/JSXPreview.js.map +1 -0
- package/dist/components/code/PackageInfo.d.ts +3 -0
- package/dist/components/code/PackageInfo.js +47 -0
- package/dist/components/code/PackageInfo.js.map +1 -0
- package/dist/components/code/Sandbox.d.ts +3 -0
- package/dist/components/code/Sandbox.js +43 -0
- package/dist/components/code/Sandbox.js.map +1 -0
- package/dist/components/code/SchemaDisplay.d.ts +4 -0
- package/dist/components/code/SchemaDisplay.js +43 -0
- package/dist/components/code/SchemaDisplay.js.map +1 -0
- package/dist/components/code/Snippet.d.ts +3 -0
- package/dist/components/code/Snippet.js +36 -0
- package/dist/components/code/Snippet.js.map +1 -0
- package/dist/components/code/StackTrace.d.ts +4 -0
- package/dist/components/code/StackTrace.js +46 -0
- package/dist/components/code/StackTrace.js.map +1 -0
- package/dist/components/code/Terminal.d.ts +4 -0
- package/dist/components/code/Terminal.js +73 -0
- package/dist/components/code/Terminal.js.map +1 -0
- package/dist/components/code/TestResults.d.ts +4 -0
- package/dist/components/code/TestResults.js +61 -0
- package/dist/components/code/TestResults.js.map +1 -0
- package/dist/components/code/WebPreview.d.ts +3 -0
- package/dist/components/code/WebPreview.js +48 -0
- package/dist/components/code/WebPreview.js.map +1 -0
- package/dist/components/display/Accordion.d.ts +12 -0
- package/dist/components/display/Accordion.js +60 -0
- package/dist/components/display/Accordion.js.map +1 -0
- package/dist/components/display/Avatar.d.ts +14 -0
- package/dist/components/display/Avatar.js +41 -0
- package/dist/components/display/Avatar.js.map +1 -0
- package/dist/components/display/Badge.d.ts +11 -0
- package/dist/components/display/Badge.js +40 -0
- package/dist/components/display/Badge.js.map +1 -0
- package/dist/components/display/Breadcrumb.d.ts +11 -0
- package/dist/components/display/Breadcrumb.js +32 -0
- package/dist/components/display/Breadcrumb.js.map +1 -0
- package/dist/components/display/Card.d.ts +14 -0
- package/dist/components/display/Card.js +61 -0
- package/dist/components/display/Card.js.map +1 -0
- package/dist/components/display/Carousel.d.ts +3 -0
- package/dist/components/display/Carousel.js +40 -0
- package/dist/components/display/Carousel.js.map +1 -0
- package/dist/components/display/Chart.d.ts +7 -0
- package/dist/components/display/Chart.js +68 -0
- package/dist/components/display/Chart.js.map +1 -0
- package/dist/components/display/Collapsible.d.ts +3 -0
- package/dist/components/display/Collapsible.js +36 -0
- package/dist/components/display/Collapsible.js.map +1 -0
- package/dist/components/display/DataTable.d.ts +4 -0
- package/dist/components/display/DataTable.js +72 -0
- package/dist/components/display/DataTable.js.map +1 -0
- package/dist/components/display/Empty.d.ts +14 -0
- package/dist/components/display/Empty.js +36 -0
- package/dist/components/display/Empty.js.map +1 -0
- package/dist/components/display/Item.d.ts +3 -0
- package/dist/components/display/Item.js +36 -0
- package/dist/components/display/Item.js.map +1 -0
- package/dist/components/display/Kbd.d.ts +7 -0
- package/dist/components/display/Kbd.js +27 -0
- package/dist/components/display/Kbd.js.map +1 -0
- package/dist/components/display/Pagination.d.ts +11 -0
- package/dist/components/display/Pagination.js +55 -0
- package/dist/components/display/Pagination.js.map +1 -0
- package/dist/components/display/Progress.d.ts +14 -0
- package/dist/components/display/Progress.js +43 -0
- package/dist/components/display/Progress.js.map +1 -0
- package/dist/components/display/Separator.d.ts +10 -0
- package/dist/components/display/Separator.js +33 -0
- package/dist/components/display/Separator.js.map +1 -0
- package/dist/components/display/Skeleton.d.ts +12 -0
- package/dist/components/display/Skeleton.js +43 -0
- package/dist/components/display/Skeleton.js.map +1 -0
- package/dist/components/display/Table.d.ts +20 -0
- package/dist/components/display/Table.js +42 -0
- package/dist/components/display/Table.js.map +1 -0
- package/dist/components/display/Tabs.d.ts +11 -0
- package/dist/components/display/Tabs.js +47 -0
- package/dist/components/display/Tabs.js.map +1 -0
- package/dist/components/display/Typography.d.ts +5 -0
- package/dist/components/display/Typography.js +45 -0
- package/dist/components/display/Typography.js.map +1 -0
- package/dist/components/feedback/Alert.d.ts +12 -0
- package/dist/components/feedback/Alert.js +41 -0
- package/dist/components/feedback/Alert.js.map +1 -0
- package/dist/components/feedback/Dialog.d.ts +17 -0
- package/dist/components/feedback/Dialog.js +90 -0
- package/dist/components/feedback/Dialog.js.map +1 -0
- package/dist/components/feedback/Spinner.d.ts +8 -0
- package/dist/components/feedback/Spinner.js +39 -0
- package/dist/components/feedback/Spinner.js.map +1 -0
- package/dist/components/feedback/Toast.d.ts +12 -0
- package/dist/components/feedback/Toast.js +50 -0
- package/dist/components/feedback/Toast.js.map +1 -0
- package/dist/components/feedback/Tooltip.d.ts +11 -0
- package/dist/components/feedback/Tooltip.js +34 -0
- package/dist/components/feedback/Tooltip.js.map +1 -0
- package/dist/components/inputs/Calendar.d.ts +3 -0
- package/dist/components/inputs/Calendar.js +81 -0
- package/dist/components/inputs/Calendar.js.map +1 -0
- package/dist/components/inputs/Checkbox.d.ts +10 -0
- package/dist/components/inputs/Checkbox.js +42 -0
- package/dist/components/inputs/Checkbox.js.map +1 -0
- package/dist/components/inputs/Combobox.d.ts +3 -0
- package/dist/components/inputs/Combobox.js +94 -0
- package/dist/components/inputs/Combobox.js.map +1 -0
- package/dist/components/inputs/DatePicker.d.ts +3 -0
- package/dist/components/inputs/DatePicker.js +56 -0
- package/dist/components/inputs/DatePicker.js.map +1 -0
- package/dist/components/inputs/Field.d.ts +5 -0
- package/dist/components/inputs/Field.js +44 -0
- package/dist/components/inputs/Field.js.map +1 -0
- package/dist/components/inputs/Input.d.ts +19 -0
- package/dist/components/inputs/Input.js +72 -0
- package/dist/components/inputs/Input.js.map +1 -0
- package/dist/components/inputs/InputGroup.d.ts +3 -0
- package/dist/components/inputs/InputGroup.js +32 -0
- package/dist/components/inputs/InputGroup.js.map +1 -0
- package/dist/components/inputs/InputOTP.d.ts +3 -0
- package/dist/components/inputs/InputOTP.js +49 -0
- package/dist/components/inputs/InputOTP.js.map +1 -0
- package/dist/components/inputs/Label.d.ts +13 -0
- package/dist/components/inputs/Label.js +33 -0
- package/dist/components/inputs/Label.js.map +1 -0
- package/dist/components/inputs/RadioGroup.d.ts +15 -0
- package/dist/components/inputs/RadioGroup.js +58 -0
- package/dist/components/inputs/RadioGroup.js.map +1 -0
- package/dist/components/inputs/Select.d.ts +12 -0
- package/dist/components/inputs/Select.js +49 -0
- package/dist/components/inputs/Select.js.map +1 -0
- package/dist/components/inputs/Slider.d.ts +16 -0
- package/dist/components/inputs/Slider.js +62 -0
- package/dist/components/inputs/Slider.js.map +1 -0
- package/dist/components/inputs/Switch.d.ts +11 -0
- package/dist/components/inputs/Switch.js +39 -0
- package/dist/components/inputs/Switch.js.map +1 -0
- package/dist/components/inputs/Textarea.d.ts +13 -0
- package/dist/components/inputs/Textarea.js +41 -0
- package/dist/components/inputs/Textarea.js.map +1 -0
- package/dist/components/inputs/Toggle.d.ts +19 -0
- package/dist/components/inputs/Toggle.js +57 -0
- package/dist/components/inputs/Toggle.js.map +1 -0
- package/dist/components/layout/AspectRatio.d.ts +3 -0
- package/dist/components/layout/AspectRatio.js +20 -0
- package/dist/components/layout/AspectRatio.js.map +1 -0
- package/dist/components/layout/Resizable.d.ts +3 -0
- package/dist/components/layout/Resizable.js +58 -0
- package/dist/components/layout/Resizable.js.map +1 -0
- package/dist/components/layout/ScrollArea.d.ts +3 -0
- package/dist/components/layout/ScrollArea.js +24 -0
- package/dist/components/layout/ScrollArea.js.map +1 -0
- package/dist/components/layout/Sidebar.d.ts +5 -0
- package/dist/components/layout/Sidebar.js +55 -0
- package/dist/components/layout/Sidebar.js.map +1 -0
- package/dist/components/overlay/AlertDialog.d.ts +3 -0
- package/dist/components/overlay/AlertDialog.js +51 -0
- package/dist/components/overlay/AlertDialog.js.map +1 -0
- package/dist/components/overlay/Command.d.ts +22 -0
- package/dist/components/overlay/Command.js +123 -0
- package/dist/components/overlay/Command.js.map +1 -0
- package/dist/components/overlay/ContextMenu.d.ts +4 -0
- package/dist/components/overlay/ContextMenu.js +66 -0
- package/dist/components/overlay/ContextMenu.js.map +1 -0
- package/dist/components/overlay/DropdownMenu.d.ts +20 -0
- package/dist/components/overlay/DropdownMenu.js +86 -0
- package/dist/components/overlay/DropdownMenu.js.map +1 -0
- package/dist/components/overlay/HoverCard.d.ts +3 -0
- package/dist/components/overlay/HoverCard.js +53 -0
- package/dist/components/overlay/HoverCard.js.map +1 -0
- package/dist/components/overlay/Menubar.d.ts +4 -0
- package/dist/components/overlay/Menubar.js +55 -0
- package/dist/components/overlay/Menubar.js.map +1 -0
- package/dist/components/overlay/NavigationMenu.d.ts +5 -0
- package/dist/components/overlay/NavigationMenu.js +42 -0
- package/dist/components/overlay/NavigationMenu.js.map +1 -0
- package/dist/components/overlay/Popover.d.ts +16 -0
- package/dist/components/overlay/Popover.js +53 -0
- package/dist/components/overlay/Popover.js.map +1 -0
- package/dist/components/overlay/Sheet.d.ts +13 -0
- package/dist/components/overlay/Sheet.js +49 -0
- package/dist/components/overlay/Sheet.js.map +1 -0
- package/dist/components/utilities/Image.d.ts +3 -0
- package/dist/components/utilities/Image.js +32 -0
- package/dist/components/utilities/Image.js.map +1 -0
- package/dist/components/utilities/OpenInChat.d.ts +3 -0
- package/dist/components/utilities/OpenInChat.js +26 -0
- package/dist/components/utilities/OpenInChat.js.map +1 -0
- package/dist/components/voice/AudioPlayer.d.ts +3 -0
- package/dist/components/voice/AudioPlayer.js +42 -0
- package/dist/components/voice/AudioPlayer.js.map +1 -0
- package/dist/components/voice/MicSelector.d.ts +3 -0
- package/dist/components/voice/MicSelector.js +36 -0
- package/dist/components/voice/MicSelector.js.map +1 -0
- package/dist/components/voice/Persona.d.ts +3 -0
- package/dist/components/voice/Persona.js +41 -0
- package/dist/components/voice/Persona.js.map +1 -0
- package/dist/components/voice/SpeechInput.d.ts +3 -0
- package/dist/components/voice/SpeechInput.js +42 -0
- package/dist/components/voice/SpeechInput.js.map +1 -0
- package/dist/components/voice/Transcription.d.ts +4 -0
- package/dist/components/voice/Transcription.js +48 -0
- package/dist/components/voice/Transcription.js.map +1 -0
- package/dist/components/voice/VoiceSelector.d.ts +3 -0
- package/dist/components/voice/VoiceSelector.js +58 -0
- package/dist/components/voice/VoiceSelector.js.map +1 -0
- package/dist/components/workflow/Flow.d.ts +20 -0
- package/dist/components/workflow/Flow.js +96 -0
- package/dist/components/workflow/Flow.js.map +1 -0
- package/dist/index.d.ts +120 -0
- package/dist/index.js +208 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +217 -0
- package/package.json +77 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
const AX_SIDEBAR_CSS = `
|
|
4
|
+
.ax-sidebar { display: flex; flex-direction: column; width: var(--sidebar-w); flex: none; height: 100%; background: var(--surface-panel); border-right: 1px solid var(--border-default); transition: width var(--dur-2) var(--ease-out); overflow: hidden; }
|
|
5
|
+
.ax-sidebar--collapsed { width: 56px; }
|
|
6
|
+
.ax-sidebar__header { padding: 16px; display: flex; align-items: center; gap: 10px; min-height: 56px; }
|
|
7
|
+
.ax-sidebar__content { flex: 1; overflow-y: auto; padding: 8px; }
|
|
8
|
+
.ax-sidebar__footer { padding: 12px 16px; border-top: 1px solid var(--border-default); }
|
|
9
|
+
.ax-sidebar__group { margin-bottom: 16px; }
|
|
10
|
+
.ax-sidebar__group-label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 6px 10px; white-space: nowrap; }
|
|
11
|
+
.ax-sidebar--collapsed .ax-sidebar__group-label { opacity: 0; }
|
|
12
|
+
.ax-sidebar__item { display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none; text-align: left; cursor: pointer; padding: 8px 10px; border-radius: var(--radius-2); color: var(--text-muted); font-family: var(--font-body); font-size: var(--text-sm); position: relative; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); white-space: nowrap; }
|
|
13
|
+
.ax-sidebar__item:hover { background: var(--surface-raised); color: var(--text-body); }
|
|
14
|
+
.ax-sidebar__item--active { background: var(--surface-raised); color: var(--text-body); }
|
|
15
|
+
.ax-sidebar__item--active::before { content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px; border-radius: 1px; background: var(--accent); }
|
|
16
|
+
.ax-sidebar__item-icon { width: 18px; height: 18px; flex: none; display: inline-flex; align-items: center; justify-content: center; }
|
|
17
|
+
.ax-sidebar__item-icon svg { width: 16px; height: 16px; }
|
|
18
|
+
.ax-sidebar__item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
|
|
19
|
+
.ax-sidebar--collapsed .ax-sidebar__item-label { opacity: 0; }
|
|
20
|
+
.ax-sidebar__item-badge { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); }
|
|
21
|
+
.ax-sidebar--collapsed .ax-sidebar__item-badge { display: none; }
|
|
22
|
+
`;
|
|
23
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-sidebar-css")) {
|
|
24
|
+
const s = document.createElement("style");
|
|
25
|
+
s.id = "ax-sidebar-css";
|
|
26
|
+
s.textContent = AX_SIDEBAR_CSS;
|
|
27
|
+
document.head.appendChild(s);
|
|
28
|
+
}
|
|
29
|
+
function Sidebar({ groups = [], activeId, onSelect, header, footer, collapsed = false, className = "", ...rest }) {
|
|
30
|
+
return /* @__PURE__ */ jsxs("aside", { className: ["ax-sidebar", collapsed ? "ax-sidebar--collapsed" : "", className].filter(Boolean).join(" "), ...rest, children: [
|
|
31
|
+
header ? /* @__PURE__ */ jsx("div", { className: "ax-sidebar__header", children: header }) : null,
|
|
32
|
+
/* @__PURE__ */ jsx("nav", { className: "ax-sidebar__content", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "ax-sidebar__group", children: [
|
|
33
|
+
g.label ? /* @__PURE__ */ jsx("div", { className: "ax-sidebar__group-label", children: g.label }) : null,
|
|
34
|
+
g.items.map((it) => /* @__PURE__ */ jsxs(
|
|
35
|
+
"button",
|
|
36
|
+
{
|
|
37
|
+
className: "ax-sidebar__item" + (it.id === activeId ? " ax-sidebar__item--active" : ""),
|
|
38
|
+
onClick: () => onSelect && onSelect(it.id),
|
|
39
|
+
title: collapsed ? it.label : void 0,
|
|
40
|
+
children: [
|
|
41
|
+
it.icon ? /* @__PURE__ */ jsx("span", { className: "ax-sidebar__item-icon", children: it.icon }) : null,
|
|
42
|
+
/* @__PURE__ */ jsx("span", { className: "ax-sidebar__item-label", children: it.label }),
|
|
43
|
+
it.badge != null ? /* @__PURE__ */ jsx("span", { className: "ax-sidebar__item-badge", children: it.badge }) : null
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
it.id
|
|
47
|
+
))
|
|
48
|
+
] }, gi)) }),
|
|
49
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "ax-sidebar__footer", children: footer }) : null
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
Sidebar
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=Sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sidebar.js","sources":["../../../src/components/layout/Sidebar.jsx"],"sourcesContent":["import React, { createContext, useContext, useState } from \"react\";\n\nconst AX_SIDEBAR_CSS = `\n.ax-sidebar { display: flex; flex-direction: column; width: var(--sidebar-w); flex: none; height: 100%; background: var(--surface-panel); border-right: 1px solid var(--border-default); transition: width var(--dur-2) var(--ease-out); overflow: hidden; }\n.ax-sidebar--collapsed { width: 56px; }\n.ax-sidebar__header { padding: 16px; display: flex; align-items: center; gap: 10px; min-height: 56px; }\n.ax-sidebar__content { flex: 1; overflow-y: auto; padding: 8px; }\n.ax-sidebar__footer { padding: 12px 16px; border-top: 1px solid var(--border-default); }\n.ax-sidebar__group { margin-bottom: 16px; }\n.ax-sidebar__group-label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 6px 10px; white-space: nowrap; }\n.ax-sidebar--collapsed .ax-sidebar__group-label { opacity: 0; }\n.ax-sidebar__item { display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none; text-align: left; cursor: pointer; padding: 8px 10px; border-radius: var(--radius-2); color: var(--text-muted); font-family: var(--font-body); font-size: var(--text-sm); position: relative; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); white-space: nowrap; }\n.ax-sidebar__item:hover { background: var(--surface-raised); color: var(--text-body); }\n.ax-sidebar__item--active { background: var(--surface-raised); color: var(--text-body); }\n.ax-sidebar__item--active::before { content: \"\"; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px; border-radius: 1px; background: var(--accent); }\n.ax-sidebar__item-icon { width: 18px; height: 18px; flex: none; display: inline-flex; align-items: center; justify-content: center; }\n.ax-sidebar__item-icon svg { width: 16px; height: 16px; }\n.ax-sidebar__item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n.ax-sidebar--collapsed .ax-sidebar__item-label { opacity: 0; }\n.ax-sidebar__item-badge { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); }\n.ax-sidebar--collapsed .ax-sidebar__item-badge { display: none; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-sidebar-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-sidebar-css\";\n s.textContent = AX_SIDEBAR_CSS;\n document.head.appendChild(s);\n}\n\nexport function Sidebar({ groups = [], activeId, onSelect, header, footer, collapsed = false, className = \"\", ...rest }) {\n return (\n <aside className={[\"ax-sidebar\", collapsed ? \"ax-sidebar--collapsed\" : \"\", className].filter(Boolean).join(\" \")} {...rest}>\n {header ? <div className=\"ax-sidebar__header\">{header}</div> : null}\n <nav className=\"ax-sidebar__content\">\n {groups.map((g, gi) => (\n <div className=\"ax-sidebar__group\" key={gi}>\n {g.label ? <div className=\"ax-sidebar__group-label\">{g.label}</div> : null}\n {g.items.map((it) => (\n <button\n key={it.id}\n className={\"ax-sidebar__item\" + (it.id === activeId ? \" ax-sidebar__item--active\" : \"\")}\n onClick={() => onSelect && onSelect(it.id)}\n title={collapsed ? it.label : undefined}\n >\n {it.icon ? <span className=\"ax-sidebar__item-icon\">{it.icon}</span> : null}\n <span className=\"ax-sidebar__item-label\">{it.label}</span>\n {it.badge != null ? <span className=\"ax-sidebar__item-badge\">{it.badge}</span> : null}\n </button>\n ))}\n </div>\n ))}\n </nav>\n {footer ? <div className=\"ax-sidebar__footer\">{footer}</div> : null}\n </aside>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBvB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,gBAAgB,GAAG;AACjF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,QAAQ,EAAE,SAAS,CAAA,GAAI,UAAU,UAAU,QAAQ,QAAQ,YAAY,OAAO,YAAY,IAAI,GAAG,QAAQ;AACvH,8BACG,SAAA,EAAM,WAAW,CAAC,cAAc,YAAY,0BAA0B,IAAI,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MAClH,UAAA;AAAA,IAAA,SAAS,oBAAC,OAAA,EAAI,WAAU,sBAAsB,kBAAO,IAAS;AAAA,IAC/D,oBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA,OAAO,IAAI,CAAC,GAAG,OACd,qBAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,MAAA,EAAE,QAAQ,oBAAC,OAAA,EAAI,WAAU,2BAA2B,UAAA,EAAE,OAAM,IAAS;AAAA,MACrE,EAAE,MAAM,IAAI,CAAC,OACZ;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,WAAW,sBAAsB,GAAG,OAAO,WAAW,8BAA8B;AAAA,UACpF,SAAS,MAAM,YAAY,SAAS,GAAG,EAAE;AAAA,UACzC,OAAO,YAAY,GAAG,QAAQ;AAAA,UAE7B,UAAA;AAAA,YAAA,GAAG,OAAO,oBAAC,QAAA,EAAK,WAAU,yBAAyB,UAAA,GAAG,MAAK,IAAU;AAAA,YACtE,oBAAC,QAAA,EAAK,WAAU,0BAA0B,aAAG,OAAM;AAAA,YAClD,GAAG,SAAS,OAAO,oBAAC,UAAK,WAAU,0BAA0B,UAAA,GAAG,MAAA,CAAM,IAAU;AAAA,UAAA;AAAA,QAAA;AAAA,QAP5E,GAAG;AAAA,MAAA,CASX;AAAA,IAAA,KAbqC,EAcxC,CACD,GACH;AAAA,IACC,SAAS,oBAAC,OAAA,EAAI,WAAU,sBAAsB,kBAAO,IAAS;AAAA,EAAA,GACjE;AAEJ;"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Confirmation modal with a tone icon and cancel/confirm actions. */
|
|
2
|
+
export interface AlertDialogProps { open?: boolean; inline?: boolean; tone?: "danger" | "warn"; title?: React.ReactNode; description?: React.ReactNode; cancelLabel?: string; confirmLabel?: string; onCancel?: () => void; onConfirm?: () => void; }
|
|
3
|
+
export declare function AlertDialog(props: AlertDialogProps): JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
const AX_ALERTDIALOG_CSS = `
|
|
4
|
+
.ax-alertdialog-overlay { position: fixed; inset: 0; z-index: 110; display: flex; align-items: center; justify-content: center; background: var(--bg-overlay); backdrop-filter: blur(var(--blur-overlay)); -webkit-backdrop-filter: blur(var(--blur-overlay)); animation: ax-ad-fade var(--dur-2) var(--ease-out); }
|
|
5
|
+
.ax-alertdialog { width: min(420px, calc(100vw - 48px)); background: var(--surface-panel); border: 1px solid var(--border-strong); border-radius: var(--radius-3); box-shadow: var(--shadow-3); padding: var(--space-6); animation: ax-ad-rise var(--dur-3) var(--ease-out); }
|
|
6
|
+
.ax-alertdialog--inline { position: relative; animation: none; box-shadow: none; }
|
|
7
|
+
.ax-alertdialog__icon { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-2); margin-bottom: var(--space-4); }
|
|
8
|
+
.ax-alertdialog__icon--danger { background: var(--danger-dim); color: var(--danger); }
|
|
9
|
+
.ax-alertdialog__icon--warn { background: var(--warn-dim); color: var(--warn); }
|
|
10
|
+
.ax-alertdialog__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-medium); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 0 0 8px; }
|
|
11
|
+
.ax-alertdialog__desc { font-size: var(--text-sm); color: var(--text-muted); margin: 0 0 var(--space-6); line-height: var(--leading-body); }
|
|
12
|
+
.ax-alertdialog__actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
|
|
13
|
+
.ax-alertdialog__btn { display: inline-flex; align-items: center; justify-content: center; height: 36px; padding: 0 16px; cursor: pointer; border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium); border: 1px solid transparent; transition: background var(--dur-1) var(--ease-out); }
|
|
14
|
+
.ax-alertdialog__btn--cancel { background: transparent; color: var(--text-muted); border-color: var(--border-strong); }
|
|
15
|
+
.ax-alertdialog__btn--cancel:hover { background: var(--surface-raised); color: var(--text-body); }
|
|
16
|
+
.ax-alertdialog__btn--confirm { background: var(--accent); color: var(--accent-fg); }
|
|
17
|
+
.ax-alertdialog__btn--confirm:hover { background: var(--accent-hover); }
|
|
18
|
+
.ax-alertdialog__btn--danger { background: var(--danger); color: #fff; }
|
|
19
|
+
.ax-alertdialog__btn--danger:hover { filter: brightness(1.1); }
|
|
20
|
+
@keyframes ax-ad-fade { from { opacity: 0; } }
|
|
21
|
+
@keyframes ax-ad-rise { from { opacity: 0; transform: translateY(8px); } }
|
|
22
|
+
@media (prefers-reduced-motion: reduce) { .ax-alertdialog-overlay, .ax-alertdialog { animation: none; } }
|
|
23
|
+
`;
|
|
24
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-alertdialog-css")) {
|
|
25
|
+
const s = document.createElement("style");
|
|
26
|
+
s.id = "ax-alertdialog-css";
|
|
27
|
+
s.textContent = AX_ALERTDIALOG_CSS;
|
|
28
|
+
document.head.appendChild(s);
|
|
29
|
+
}
|
|
30
|
+
const Warn = /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
31
|
+
/* @__PURE__ */ jsx("path", { d: "M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" }),
|
|
32
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" })
|
|
33
|
+
] });
|
|
34
|
+
function AlertDialog({ open = true, inline = false, tone = "danger", title, description, cancelLabel = "Cancel", confirmLabel = "Confirm", onCancel, onConfirm, className = "", ...rest }) {
|
|
35
|
+
if (!open) return null;
|
|
36
|
+
const panel = /* @__PURE__ */ jsxs("div", { className: ["ax-alertdialog", inline ? "ax-alertdialog--inline" : "", className].filter(Boolean).join(" "), role: "alertdialog", "aria-modal": !inline, onClick: (e) => e.stopPropagation(), ...rest, children: [
|
|
37
|
+
/* @__PURE__ */ jsx("div", { className: "ax-alertdialog__icon ax-alertdialog__icon--" + (tone === "warn" ? "warn" : "danger"), children: Warn }),
|
|
38
|
+
/* @__PURE__ */ jsx("h2", { className: "ax-alertdialog__title", children: title }),
|
|
39
|
+
description ? /* @__PURE__ */ jsx("p", { className: "ax-alertdialog__desc", children: description }) : null,
|
|
40
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-alertdialog__actions", children: [
|
|
41
|
+
/* @__PURE__ */ jsx("button", { className: "ax-alertdialog__btn ax-alertdialog__btn--cancel", onClick: onCancel, children: cancelLabel }),
|
|
42
|
+
/* @__PURE__ */ jsx("button", { className: "ax-alertdialog__btn " + (tone === "danger" ? "ax-alertdialog__btn--danger" : "ax-alertdialog__btn--confirm"), onClick: onConfirm, children: confirmLabel })
|
|
43
|
+
] })
|
|
44
|
+
] });
|
|
45
|
+
if (inline) return panel;
|
|
46
|
+
return /* @__PURE__ */ jsx("div", { className: "ax-alertdialog-overlay", onClick: onCancel, children: panel });
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
AlertDialog
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=AlertDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlertDialog.js","sources":["../../../src/components/overlay/AlertDialog.jsx"],"sourcesContent":["import React from \"react\";\n\nconst AX_ALERTDIALOG_CSS = `\n.ax-alertdialog-overlay { position: fixed; inset: 0; z-index: 110; display: flex; align-items: center; justify-content: center; background: var(--bg-overlay); backdrop-filter: blur(var(--blur-overlay)); -webkit-backdrop-filter: blur(var(--blur-overlay)); animation: ax-ad-fade var(--dur-2) var(--ease-out); }\n.ax-alertdialog { width: min(420px, calc(100vw - 48px)); background: var(--surface-panel); border: 1px solid var(--border-strong); border-radius: var(--radius-3); box-shadow: var(--shadow-3); padding: var(--space-6); animation: ax-ad-rise var(--dur-3) var(--ease-out); }\n.ax-alertdialog--inline { position: relative; animation: none; box-shadow: none; }\n.ax-alertdialog__icon { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-2); margin-bottom: var(--space-4); }\n.ax-alertdialog__icon--danger { background: var(--danger-dim); color: var(--danger); }\n.ax-alertdialog__icon--warn { background: var(--warn-dim); color: var(--warn); }\n.ax-alertdialog__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-medium); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 0 0 8px; }\n.ax-alertdialog__desc { font-size: var(--text-sm); color: var(--text-muted); margin: 0 0 var(--space-6); line-height: var(--leading-body); }\n.ax-alertdialog__actions { display: flex; justify-content: flex-end; gap: var(--space-2); }\n.ax-alertdialog__btn { display: inline-flex; align-items: center; justify-content: center; height: 36px; padding: 0 16px; cursor: pointer; border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium); border: 1px solid transparent; transition: background var(--dur-1) var(--ease-out); }\n.ax-alertdialog__btn--cancel { background: transparent; color: var(--text-muted); border-color: var(--border-strong); }\n.ax-alertdialog__btn--cancel:hover { background: var(--surface-raised); color: var(--text-body); }\n.ax-alertdialog__btn--confirm { background: var(--accent); color: var(--accent-fg); }\n.ax-alertdialog__btn--confirm:hover { background: var(--accent-hover); }\n.ax-alertdialog__btn--danger { background: var(--danger); color: #fff; }\n.ax-alertdialog__btn--danger:hover { filter: brightness(1.1); }\n@keyframes ax-ad-fade { from { opacity: 0; } }\n@keyframes ax-ad-rise { from { opacity: 0; transform: translateY(8px); } }\n@media (prefers-reduced-motion: reduce) { .ax-alertdialog-overlay, .ax-alertdialog { animation: none; } }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-alertdialog-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-alertdialog-css\";\n s.textContent = AX_ALERTDIALOG_CSS;\n document.head.appendChild(s);\n}\n\nconst Warn = <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z\"></path><path d=\"M12 9v4M12 17h.01\"></path></svg>;\n\nexport function AlertDialog({ open = true, inline = false, tone = \"danger\", title, description, cancelLabel = \"Cancel\", confirmLabel = \"Confirm\", onCancel, onConfirm, className = \"\", ...rest }) {\n if (!open) return null;\n const panel = (\n <div className={[\"ax-alertdialog\", inline ? \"ax-alertdialog--inline\" : \"\", className].filter(Boolean).join(\" \")} role=\"alertdialog\" aria-modal={!inline} onClick={(e) => e.stopPropagation()} {...rest}>\n <div className={\"ax-alertdialog__icon ax-alertdialog__icon--\" + (tone === \"warn\" ? \"warn\" : \"danger\")}>{Warn}</div>\n <h2 className=\"ax-alertdialog__title\">{title}</h2>\n {description ? <p className=\"ax-alertdialog__desc\">{description}</p> : null}\n <div className=\"ax-alertdialog__actions\">\n <button className=\"ax-alertdialog__btn ax-alertdialog__btn--cancel\" onClick={onCancel}>{cancelLabel}</button>\n <button className={\"ax-alertdialog__btn \" + (tone === \"danger\" ? \"ax-alertdialog__btn--danger\" : \"ax-alertdialog__btn--confirm\")} onClick={onConfirm}>{confirmLabel}</button>\n </div>\n </div>\n );\n if (inline) return panel;\n return <div className=\"ax-alertdialog-overlay\" onClick={onCancel}>{panel}</div>;\n}\n"],"names":[],"mappings":";;AAEA,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB3B,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,oBAAoB,GAAG;AACrF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEA,MAAM,OAAO,qBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,gFAAA,CAAgF;AAAA,EAAO,oBAAC,QAAA,EAAK,GAAE,oBAAA,CAAoB;AAAA,GAAO;AAEvR,SAAS,YAAY,EAAE,OAAO,MAAM,SAAS,OAAO,OAAO,UAAU,OAAO,aAAa,cAAc,UAAU,eAAe,WAAW,UAAU,WAAW,YAAY,IAAI,GAAG,QAAQ;AAChM,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QACJ,qBAAC,OAAA,EAAI,WAAW,CAAC,kBAAkB,SAAS,2BAA2B,IAAI,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAG,MAAK,eAAc,cAAY,CAAC,QAAQ,SAAS,CAAC,MAAM,EAAE,gBAAA,GAAoB,GAAG,MAChM,UAAA;AAAA,IAAA,oBAAC,SAAI,WAAW,iDAAiD,SAAS,SAAS,SAAS,WAAY,UAAA,KAAA,CAAK;AAAA,IAC7G,oBAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IAC5C,cAAc,oBAAC,KAAA,EAAE,WAAU,wBAAwB,uBAAY,IAAO;AAAA,IACvE,qBAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,MAAA,oBAAC,UAAA,EAAO,WAAU,mDAAkD,SAAS,UAAW,UAAA,aAAY;AAAA,MACpG,oBAAC,UAAA,EAAO,WAAW,0BAA0B,SAAS,WAAW,gCAAgC,iCAAiC,SAAS,WAAY,UAAA,aAAA,CAAa;AAAA,IAAA,EAAA,CACtK;AAAA,EAAA,GACF;AAEF,MAAI,OAAQ,QAAO;AACnB,6BAAQ,OAAA,EAAI,WAAU,0BAAyB,SAAS,UAAW,UAAA,OAAM;AAC3E;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @startingPoint section="Overlay" subtitle="⌘K command palette — search + keyboard nav" viewport="600x420"
|
|
3
|
+
* Command palette: fuzzy filter, ↑/↓/↵ keyboard nav, grouped results.
|
|
4
|
+
*/
|
|
5
|
+
export interface CommandItem {
|
|
6
|
+
id?: string;
|
|
7
|
+
label: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CommandProps {
|
|
12
|
+
/** @default true */
|
|
13
|
+
open?: boolean;
|
|
14
|
+
/** Render without the fixed overlay (docs/specimens). @default false */
|
|
15
|
+
inline?: boolean;
|
|
16
|
+
/** Grouped commands: { label, items }. */
|
|
17
|
+
groups: Array<{ label?: string; items: CommandItem[] }>;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
onClose?: () => void;
|
|
20
|
+
onSelect?: (item: CommandItem) => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function Command(props: CommandProps): JSX.Element;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useMemo, useEffect } from "react";
|
|
3
|
+
const AX_COMMAND_CSS = `
|
|
4
|
+
.ax-cmd-overlay {
|
|
5
|
+
position: fixed; inset: 0; z-index: 100; display: flex; align-items: flex-start; justify-content: center;
|
|
6
|
+
padding-top: 14vh; background: var(--bg-overlay);
|
|
7
|
+
backdrop-filter: blur(var(--blur-overlay)); -webkit-backdrop-filter: blur(var(--blur-overlay));
|
|
8
|
+
animation: ax-cmd-fade var(--dur-2) var(--ease-out);
|
|
9
|
+
}
|
|
10
|
+
.ax-cmd {
|
|
11
|
+
width: min(560px, calc(100vw - 48px)); max-height: 60vh; display: flex; flex-direction: column;
|
|
12
|
+
background: var(--surface-panel); border: 1px solid var(--border-strong);
|
|
13
|
+
border-radius: var(--radius-3); box-shadow: var(--shadow-3); overflow: hidden;
|
|
14
|
+
animation: ax-cmd-rise var(--dur-3) var(--ease-out);
|
|
15
|
+
}
|
|
16
|
+
.ax-cmd--inline { position: relative; animation: none; max-height: 340px; }
|
|
17
|
+
.ax-cmd__head { display: flex; align-items: center; gap: 10px; padding: 0 14px; border-bottom: 1px solid var(--border-default); }
|
|
18
|
+
.ax-cmd__icon { color: var(--text-faint); flex: none; }
|
|
19
|
+
.ax-cmd__input { flex: 1; height: 48px; background: none; border: none; outline: none; color: var(--text-body); font-family: var(--font-body); font-size: var(--text-md); }
|
|
20
|
+
.ax-cmd__input::placeholder { color: var(--text-faint); }
|
|
21
|
+
.ax-cmd__esc { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; }
|
|
22
|
+
.ax-cmd__list { overflow-y: auto; padding: var(--space-1); }
|
|
23
|
+
.ax-cmd__group-label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }
|
|
24
|
+
.ax-cmd__item {
|
|
25
|
+
display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none;
|
|
26
|
+
text-align: left; cursor: pointer; padding: 9px 10px; border-radius: var(--radius-2);
|
|
27
|
+
color: var(--text-body); font-family: var(--font-body); font-size: var(--text-sm);
|
|
28
|
+
}
|
|
29
|
+
.ax-cmd__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }
|
|
30
|
+
.ax-cmd__item--active { background: var(--surface-raised); }
|
|
31
|
+
.ax-cmd__item-shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }
|
|
32
|
+
.ax-cmd__empty { padding: 28px; text-align: center; color: var(--text-faint); font-size: var(--text-sm); }
|
|
33
|
+
@keyframes ax-cmd-fade { from { opacity: 0; } }
|
|
34
|
+
@keyframes ax-cmd-rise { from { opacity: 0; transform: translateY(-8px); } }
|
|
35
|
+
@media (prefers-reduced-motion: reduce) { .ax-cmd-overlay, .ax-cmd { animation: none; } }
|
|
36
|
+
`;
|
|
37
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-command-css")) {
|
|
38
|
+
const s = document.createElement("style");
|
|
39
|
+
s.id = "ax-command-css";
|
|
40
|
+
s.textContent = AX_COMMAND_CSS;
|
|
41
|
+
document.head.appendChild(s);
|
|
42
|
+
}
|
|
43
|
+
function Command({ open = true, inline = false, groups = [], placeholder = "Type a command or search…", onClose, onSelect, className = "", ...rest }) {
|
|
44
|
+
const [query, setQuery] = useState("");
|
|
45
|
+
const [active, setActive] = useState(0);
|
|
46
|
+
const inputRef = useRef(null);
|
|
47
|
+
const flat = useMemo(() => {
|
|
48
|
+
const q = query.trim().toLowerCase();
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const g of groups) {
|
|
51
|
+
const matched = g.items.filter((it) => !q || it.label.toLowerCase().includes(q));
|
|
52
|
+
if (matched.length) out.push({ label: g.label, items: matched });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}, [groups, query]);
|
|
56
|
+
const flatItems = useMemo(() => flat.flatMap((g) => g.items), [flat]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
setActive(0);
|
|
59
|
+
}, [query]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (open && inputRef.current) inputRef.current.focus();
|
|
62
|
+
}, [open]);
|
|
63
|
+
if (!open) return null;
|
|
64
|
+
const choose = (it) => {
|
|
65
|
+
onSelect && onSelect(it);
|
|
66
|
+
onClose && onClose();
|
|
67
|
+
};
|
|
68
|
+
const onKey = (e) => {
|
|
69
|
+
if (e.key === "ArrowDown") {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
setActive((a) => Math.min(a + 1, flatItems.length - 1));
|
|
72
|
+
} else if (e.key === "ArrowUp") {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
setActive((a) => Math.max(a - 1, 0));
|
|
75
|
+
} else if (e.key === "Enter") {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
if (flatItems[active]) choose(flatItems[active]);
|
|
78
|
+
} else if (e.key === "Escape") {
|
|
79
|
+
onClose && onClose();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
let idx = -1;
|
|
83
|
+
const panel = /* @__PURE__ */ jsxs("div", { className: ["ax-cmd", inline ? "ax-cmd--inline" : "", className].filter(Boolean).join(" "), onClick: (e) => e.stopPropagation(), ...rest, children: [
|
|
84
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-cmd__head", children: [
|
|
85
|
+
/* @__PURE__ */ jsxs("svg", { className: "ax-cmd__icon", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
|
|
86
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
87
|
+
/* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsx("input", { ref: inputRef, className: "ax-cmd__input", placeholder, value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: onKey }),
|
|
90
|
+
/* @__PURE__ */ jsx("span", { className: "ax-cmd__esc", children: "ESC" })
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-cmd__list", children: [
|
|
93
|
+
flatItems.length === 0 ? /* @__PURE__ */ jsx("div", { className: "ax-cmd__empty", children: "No results." }) : null,
|
|
94
|
+
flat.map((g) => /* @__PURE__ */ jsxs("div", { children: [
|
|
95
|
+
g.label ? /* @__PURE__ */ jsx("div", { className: "ax-cmd__group-label", children: g.label }) : null,
|
|
96
|
+
g.items.map((it) => {
|
|
97
|
+
idx++;
|
|
98
|
+
const myIdx = idx;
|
|
99
|
+
return /* @__PURE__ */ jsxs(
|
|
100
|
+
"button",
|
|
101
|
+
{
|
|
102
|
+
className: "ax-cmd__item" + (myIdx === active ? " ax-cmd__item--active" : ""),
|
|
103
|
+
onMouseEnter: () => setActive(myIdx),
|
|
104
|
+
onClick: () => choose(it),
|
|
105
|
+
children: [
|
|
106
|
+
it.icon,
|
|
107
|
+
/* @__PURE__ */ jsx("span", { children: it.label }),
|
|
108
|
+
it.shortcut ? /* @__PURE__ */ jsx("span", { className: "ax-cmd__item-shortcut", children: it.shortcut }) : null
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
it.id || it.label
|
|
112
|
+
);
|
|
113
|
+
})
|
|
114
|
+
] }, g.label))
|
|
115
|
+
] })
|
|
116
|
+
] });
|
|
117
|
+
if (inline) return panel;
|
|
118
|
+
return /* @__PURE__ */ jsx("div", { className: "ax-cmd-overlay", onClick: onClose, children: panel });
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
Command
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=Command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Command.js","sources":["../../../src/components/overlay/Command.jsx"],"sourcesContent":["import React, { useState, useMemo, useEffect, useRef } from \"react\";\n\nconst AX_COMMAND_CSS = `\n.ax-cmd-overlay {\n position: fixed; inset: 0; z-index: 100; display: flex; align-items: flex-start; justify-content: center;\n padding-top: 14vh; background: var(--bg-overlay);\n backdrop-filter: blur(var(--blur-overlay)); -webkit-backdrop-filter: blur(var(--blur-overlay));\n animation: ax-cmd-fade var(--dur-2) var(--ease-out);\n}\n.ax-cmd {\n width: min(560px, calc(100vw - 48px)); max-height: 60vh; display: flex; flex-direction: column;\n background: var(--surface-panel); border: 1px solid var(--border-strong);\n border-radius: var(--radius-3); box-shadow: var(--shadow-3); overflow: hidden;\n animation: ax-cmd-rise var(--dur-3) var(--ease-out);\n}\n.ax-cmd--inline { position: relative; animation: none; max-height: 340px; }\n.ax-cmd__head { display: flex; align-items: center; gap: 10px; padding: 0 14px; border-bottom: 1px solid var(--border-default); }\n.ax-cmd__icon { color: var(--text-faint); flex: none; }\n.ax-cmd__input { flex: 1; height: 48px; background: none; border: none; outline: none; color: var(--text-body); font-family: var(--font-body); font-size: var(--text-md); }\n.ax-cmd__input::placeholder { color: var(--text-faint); }\n.ax-cmd__esc { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; }\n.ax-cmd__list { overflow-y: auto; padding: var(--space-1); }\n.ax-cmd__group-label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }\n.ax-cmd__item {\n display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none;\n text-align: left; cursor: pointer; padding: 9px 10px; border-radius: var(--radius-2);\n color: var(--text-body); font-family: var(--font-body); font-size: var(--text-sm);\n}\n.ax-cmd__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }\n.ax-cmd__item--active { background: var(--surface-raised); }\n.ax-cmd__item-shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }\n.ax-cmd__empty { padding: 28px; text-align: center; color: var(--text-faint); font-size: var(--text-sm); }\n@keyframes ax-cmd-fade { from { opacity: 0; } }\n@keyframes ax-cmd-rise { from { opacity: 0; transform: translateY(-8px); } }\n@media (prefers-reduced-motion: reduce) { .ax-cmd-overlay, .ax-cmd { animation: none; } }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-command-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-command-css\";\n s.textContent = AX_COMMAND_CSS;\n document.head.appendChild(s);\n}\n\nexport function Command({ open = true, inline = false, groups = [], placeholder = \"Type a command or search…\", onClose, onSelect, className = \"\", ...rest }) {\n const [query, setQuery] = useState(\"\");\n const [active, setActive] = useState(0);\n const inputRef = useRef(null);\n\n const flat = useMemo(() => {\n const q = query.trim().toLowerCase();\n const out = [];\n for (const g of groups) {\n const matched = g.items.filter((it) => !q || it.label.toLowerCase().includes(q));\n if (matched.length) out.push({ label: g.label, items: matched });\n }\n return out;\n }, [groups, query]);\n\n const flatItems = useMemo(() => flat.flatMap((g) => g.items), [flat]);\n\n useEffect(() => { setActive(0); }, [query]);\n useEffect(() => { if (open && inputRef.current) inputRef.current.focus(); }, [open]);\n\n if (!open) return null;\n\n const choose = (it) => { onSelect && onSelect(it); onClose && onClose(); };\n\n const onKey = (e) => {\n if (e.key === \"ArrowDown\") { e.preventDefault(); setActive((a) => Math.min(a + 1, flatItems.length - 1)); }\n else if (e.key === \"ArrowUp\") { e.preventDefault(); setActive((a) => Math.max(a - 1, 0)); }\n else if (e.key === \"Enter\") { e.preventDefault(); if (flatItems[active]) choose(flatItems[active]); }\n else if (e.key === \"Escape\") { onClose && onClose(); }\n };\n\n let idx = -1;\n const panel = (\n <div className={[\"ax-cmd\", inline ? \"ax-cmd--inline\" : \"\", className].filter(Boolean).join(\" \")} onClick={(e) => e.stopPropagation()} {...rest}>\n <div className=\"ax-cmd__head\">\n <svg className=\"ax-cmd__icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><path d=\"m21 21-4.3-4.3\"></path></svg>\n <input ref={inputRef} className=\"ax-cmd__input\" placeholder={placeholder} value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={onKey} />\n <span className=\"ax-cmd__esc\">ESC</span>\n </div>\n <div className=\"ax-cmd__list\">\n {flatItems.length === 0 ? <div className=\"ax-cmd__empty\">No results.</div> : null}\n {flat.map((g) => (\n <div key={g.label}>\n {g.label ? <div className=\"ax-cmd__group-label\">{g.label}</div> : null}\n {g.items.map((it) => {\n idx++;\n const myIdx = idx;\n return (\n <button\n key={it.id || it.label}\n className={\"ax-cmd__item\" + (myIdx === active ? \" ax-cmd__item--active\" : \"\")}\n onMouseEnter={() => setActive(myIdx)}\n onClick={() => choose(it)}\n >\n {it.icon}\n <span>{it.label}</span>\n {it.shortcut ? <span className=\"ax-cmd__item-shortcut\">{it.shortcut}</span> : null}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n );\n\n if (inline) return panel;\n return <div className=\"ax-cmd-overlay\" onClick={onClose}>{panel}</div>;\n}\n"],"names":[],"mappings":";;AAEA,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCvB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,gBAAgB,GAAG;AACjF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,QAAQ,EAAE,OAAO,MAAM,SAAS,OAAO,SAAS,CAAA,GAAI,cAAc,6BAA6B,SAAS,UAAU,YAAY,IAAI,GAAG,QAAQ;AAC3J,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,CAAC;AACtC,QAAM,WAAW,OAAO,IAAI;AAE5B,QAAM,OAAO,QAAQ,MAAM;AACzB,UAAM,IAAI,MAAM,KAAA,EAAO,YAAA;AACvB,UAAM,MAAM,CAAA;AACZ,eAAW,KAAK,QAAQ;AACtB,YAAM,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,GAAG,MAAM,YAAA,EAAc,SAAS,CAAC,CAAC;AAC/E,UAAI,QAAQ,OAAQ,KAAI,KAAK,EAAE,OAAO,EAAE,OAAO,OAAO,SAAS;AAAA,IACjE;AACA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,QAAM,YAAY,QAAQ,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC;AAEpE,YAAU,MAAM;AAAE,cAAU,CAAC;AAAA,EAAG,GAAG,CAAC,KAAK,CAAC;AAC1C,YAAU,MAAM;AAAE,QAAI,QAAQ,SAAS,QAAS,UAAS,QAAQ,MAAA;AAAA,EAAS,GAAG,CAAC,IAAI,CAAC;AAEnF,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,SAAS,CAAC,OAAO;AAAE,gBAAY,SAAS,EAAE;AAAG,eAAW,QAAA;AAAA,EAAW;AAEzE,QAAM,QAAQ,CAAC,MAAM;AACnB,QAAI,EAAE,QAAQ,aAAa;AAAE,QAAE,eAAA;AAAkB,gBAAU,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,UAAU,SAAS,CAAC,CAAC;AAAA,IAAG,WACjG,EAAE,QAAQ,WAAW;AAAE,QAAE,eAAA;AAAkB,gBAAU,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IAAG,WACjF,EAAE,QAAQ,SAAS;AAAE,QAAE,eAAA;AAAkB,UAAI,UAAU,MAAM,EAAG,QAAO,UAAU,MAAM,CAAC;AAAA,IAAG,WAC3F,EAAE,QAAQ,UAAU;AAAE,iBAAW,QAAA;AAAA,IAAW;AAAA,EACvD;AAEA,MAAI,MAAM;AACV,QAAM,QACJ,qBAAC,OAAA,EAAI,WAAW,CAAC,UAAU,SAAS,mBAAmB,IAAI,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,gBAAA,GAAoB,GAAG,MACxI,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,gBACb,UAAA;AAAA,MAAA,qBAAC,SAAI,WAAU,gBAAe,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,UAAA;AAAA,QAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAAS,oBAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB;AAAA,MAAA,GAAO;AAAA,0BACvN,SAAA,EAAM,KAAK,UAAU,WAAU,iBAAgB,aAA0B,OAAO,OAAO,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK,GAAG,WAAW,OAAO;AAAA,MACrJ,oBAAC,QAAA,EAAK,WAAU,eAAc,UAAA,MAAA,CAAG;AAAA,IAAA,GACnC;AAAA,IACA,qBAAC,OAAA,EAAI,WAAU,gBACZ,UAAA;AAAA,MAAA,UAAU,WAAW,IAAI,oBAAC,SAAI,WAAU,iBAAgB,yBAAW,IAAS;AAAA,MAC5E,KAAK,IAAI,CAAC,2BACR,OAAA,EACE,UAAA;AAAA,QAAA,EAAE,QAAQ,oBAAC,OAAA,EAAI,WAAU,uBAAuB,UAAA,EAAE,OAAM,IAAS;AAAA,QACjE,EAAE,MAAM,IAAI,CAAC,OAAO;AACnB;AACA,gBAAM,QAAQ;AACd,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAW,kBAAkB,UAAU,SAAS,0BAA0B;AAAA,cAC1E,cAAc,MAAM,UAAU,KAAK;AAAA,cACnC,SAAS,MAAM,OAAO,EAAE;AAAA,cAEvB,UAAA;AAAA,gBAAA,GAAG;AAAA,gBACJ,oBAAC,QAAA,EAAM,UAAA,GAAG,MAAA,CAAM;AAAA,gBACf,GAAG,WAAW,oBAAC,QAAA,EAAK,WAAU,yBAAyB,UAAA,GAAG,UAAS,IAAU;AAAA,cAAA;AAAA,YAAA;AAAA,YAPzE,GAAG,MAAM,GAAG;AAAA,UAAA;AAAA,QAUvB,CAAC;AAAA,MAAA,EAAA,GAjBO,EAAE,KAkBZ,CACD;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GACF;AAGF,MAAI,OAAQ,QAAO;AACnB,6BAAQ,OAAA,EAAI,WAAU,kBAAiB,SAAS,SAAU,UAAA,OAAM;AAClE;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Right-click context menu; items support icons, shortcuts, danger, separators, labels. */
|
|
2
|
+
export interface ContextMenuItem { label?: React.ReactNode; icon?: React.ReactNode; shortcut?: string; danger?: boolean; onSelect?: () => void; type?: "separator" | "label"; }
|
|
3
|
+
export interface ContextMenuProps { items: ContextMenuItem[]; children?: React.ReactNode; }
|
|
4
|
+
export declare function ContextMenu(props: ContextMenuProps): JSX.Element;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useRef, useCallback, useEffect } from "react";
|
|
3
|
+
const AX_CTXMENU_CSS = `
|
|
4
|
+
.ax-ctxmenu-trigger { display: contents; }
|
|
5
|
+
.ax-ctxmenu { position: fixed; z-index: 80; min-width: 190px; background: var(--surface-panel); border: 1px solid var(--border-strong); border-radius: var(--radius-3); box-shadow: var(--shadow-2); padding: var(--space-1); animation: ax-ctxmenu-in var(--dur-1) var(--ease-out); }
|
|
6
|
+
.ax-ctxmenu__item { display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none; text-align: left; cursor: pointer; padding: 7px 10px; border-radius: var(--radius-2); color: var(--text-body); font-family: var(--font-body); font-size: var(--text-sm); }
|
|
7
|
+
.ax-ctxmenu__item:hover { background: var(--surface-raised); }
|
|
8
|
+
.ax-ctxmenu__item--danger { color: var(--danger); }
|
|
9
|
+
.ax-ctxmenu__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }
|
|
10
|
+
.ax-ctxmenu__item--danger svg { color: var(--danger); }
|
|
11
|
+
.ax-ctxmenu__shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }
|
|
12
|
+
.ax-ctxmenu__sep { height: 1px; background: var(--border-default); margin: var(--space-1) 0; }
|
|
13
|
+
.ax-ctxmenu__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }
|
|
14
|
+
@keyframes ax-ctxmenu-in { from { opacity: 0; transform: scale(0.97); } }
|
|
15
|
+
@media (prefers-reduced-motion: reduce) { .ax-ctxmenu { animation: none; } }
|
|
16
|
+
`;
|
|
17
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-ctxmenu-css")) {
|
|
18
|
+
const s = document.createElement("style");
|
|
19
|
+
s.id = "ax-ctxmenu-css";
|
|
20
|
+
s.textContent = AX_CTXMENU_CSS;
|
|
21
|
+
document.head.appendChild(s);
|
|
22
|
+
}
|
|
23
|
+
function ContextMenu({ items = [], children, className = "", ...rest }) {
|
|
24
|
+
const [menu, setMenu] = useState(null);
|
|
25
|
+
const ref = useRef(null);
|
|
26
|
+
const onContext = (e) => {
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
setMenu({ x: e.clientX, y: e.clientY });
|
|
29
|
+
};
|
|
30
|
+
const close = useCallback(() => setMenu(null), []);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (menu) {
|
|
33
|
+
const onDoc = () => close();
|
|
34
|
+
const onKey = (e) => {
|
|
35
|
+
if (e.key === "Escape") close();
|
|
36
|
+
};
|
|
37
|
+
document.addEventListener("mousedown", onDoc);
|
|
38
|
+
document.addEventListener("keydown", onKey);
|
|
39
|
+
document.addEventListener("scroll", onDoc, true);
|
|
40
|
+
return () => {
|
|
41
|
+
document.removeEventListener("mousedown", onDoc);
|
|
42
|
+
document.removeEventListener("keydown", onKey);
|
|
43
|
+
document.removeEventListener("scroll", onDoc, true);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}, [menu, close]);
|
|
47
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
48
|
+
/* @__PURE__ */ jsx("div", { className: "ax-ctxmenu-trigger", onContextMenu: onContext, ref, ...rest, children }),
|
|
49
|
+
menu ? /* @__PURE__ */ jsx("div", { className: ["ax-ctxmenu", className].filter(Boolean).join(" "), style: { left: menu.x, top: menu.y }, onClick: (e) => e.stopPropagation(), children: items.map((it, i) => {
|
|
50
|
+
if (it.type === "separator") return /* @__PURE__ */ jsx("div", { className: "ax-ctxmenu__sep" }, i);
|
|
51
|
+
if (it.type === "label") return /* @__PURE__ */ jsx("div", { className: "ax-ctxmenu__label", children: it.label }, i);
|
|
52
|
+
return /* @__PURE__ */ jsxs("button", { className: "ax-ctxmenu__item" + (it.danger ? " ax-ctxmenu__item--danger" : ""), onClick: () => {
|
|
53
|
+
close();
|
|
54
|
+
it.onSelect && it.onSelect();
|
|
55
|
+
}, children: [
|
|
56
|
+
it.icon,
|
|
57
|
+
/* @__PURE__ */ jsx("span", { children: it.label }),
|
|
58
|
+
it.shortcut ? /* @__PURE__ */ jsx("span", { className: "ax-ctxmenu__shortcut", children: it.shortcut }) : null
|
|
59
|
+
] }, i);
|
|
60
|
+
}) }) : null
|
|
61
|
+
] });
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
ContextMenu
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=ContextMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextMenu.js","sources":["../../../src/components/overlay/ContextMenu.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\n\nconst AX_CTXMENU_CSS = `\n.ax-ctxmenu-trigger { display: contents; }\n.ax-ctxmenu { position: fixed; z-index: 80; min-width: 190px; background: var(--surface-panel); border: 1px solid var(--border-strong); border-radius: var(--radius-3); box-shadow: var(--shadow-2); padding: var(--space-1); animation: ax-ctxmenu-in var(--dur-1) var(--ease-out); }\n.ax-ctxmenu__item { display: flex; align-items: center; gap: 10px; width: 100%; appearance: none; background: none; border: none; text-align: left; cursor: pointer; padding: 7px 10px; border-radius: var(--radius-2); color: var(--text-body); font-family: var(--font-body); font-size: var(--text-sm); }\n.ax-ctxmenu__item:hover { background: var(--surface-raised); }\n.ax-ctxmenu__item--danger { color: var(--danger); }\n.ax-ctxmenu__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }\n.ax-ctxmenu__item--danger svg { color: var(--danger); }\n.ax-ctxmenu__shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }\n.ax-ctxmenu__sep { height: 1px; background: var(--border-default); margin: var(--space-1) 0; }\n.ax-ctxmenu__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }\n@keyframes ax-ctxmenu-in { from { opacity: 0; transform: scale(0.97); } }\n@media (prefers-reduced-motion: reduce) { .ax-ctxmenu { animation: none; } }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-ctxmenu-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-ctxmenu-css\";\n s.textContent = AX_CTXMENU_CSS;\n document.head.appendChild(s);\n}\n\nexport function ContextMenu({ items = [], children, className = \"\", ...rest }) {\n const [menu, setMenu] = useState(null); // {x,y}\n const ref = useRef(null);\n\n const onContext = (e) => { e.preventDefault(); setMenu({ x: e.clientX, y: e.clientY }); };\n const close = useCallback(() => setMenu(null), []);\n useEffect(() => {\n if (menu) {\n const onDoc = () => close();\n const onKey = (e) => { if (e.key === \"Escape\") close(); };\n document.addEventListener(\"mousedown\", onDoc);\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(\"scroll\", onDoc, true);\n return () => { document.removeEventListener(\"mousedown\", onDoc); document.removeEventListener(\"keydown\", onKey); document.removeEventListener(\"scroll\", onDoc, true); };\n }\n }, [menu, close]);\n\n return (\n <React.Fragment>\n <div className=\"ax-ctxmenu-trigger\" onContextMenu={onContext} ref={ref} {...rest}>{children}</div>\n {menu ? (\n <div className={[\"ax-ctxmenu\", className].filter(Boolean).join(\" \")} style={{ left: menu.x, top: menu.y }} onClick={(e) => e.stopPropagation()}>\n {items.map((it, i) => {\n if (it.type === \"separator\") return <div key={i} className=\"ax-ctxmenu__sep\"></div>;\n if (it.type === \"label\") return <div key={i} className=\"ax-ctxmenu__label\">{it.label}</div>;\n return (\n <button key={i} className={\"ax-ctxmenu__item\" + (it.danger ? \" ax-ctxmenu__item--danger\" : \"\")} onClick={() => { close(); it.onSelect && it.onSelect(); }}>\n {it.icon}<span>{it.label}</span>{it.shortcut ? <span className=\"ax-ctxmenu__shortcut\">{it.shortcut}</span> : null}\n </button>\n );\n })}\n </div>\n ) : null}\n </React.Fragment>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAevB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,gBAAgB,GAAG;AACjF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,YAAY,EAAE,QAAQ,IAAI,UAAU,YAAY,IAAI,GAAG,QAAQ;AAC7E,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,IAAI;AACrC,QAAM,MAAM,OAAO,IAAI;AAEvB,QAAM,YAAY,CAAC,MAAM;AAAE,MAAE,eAAA;AAAkB,YAAQ,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,SAAS;AAAA,EAAG;AACxF,QAAM,QAAQ,YAAY,MAAM,QAAQ,IAAI,GAAG,CAAA,CAAE;AACjD,YAAU,MAAM;AACd,QAAI,MAAM;AACR,YAAM,QAAQ,MAAM,MAAA;AACpB,YAAM,QAAQ,CAAC,MAAM;AAAE,YAAI,EAAE,QAAQ,SAAU,OAAA;AAAA,MAAS;AACxD,eAAS,iBAAiB,aAAa,KAAK;AAC5C,eAAS,iBAAiB,WAAW,KAAK;AAC1C,eAAS,iBAAiB,UAAU,OAAO,IAAI;AAC/C,aAAO,MAAM;AAAE,iBAAS,oBAAoB,aAAa,KAAK;AAAG,iBAAS,oBAAoB,WAAW,KAAK;AAAG,iBAAS,oBAAoB,UAAU,OAAO,IAAI;AAAA,MAAG;AAAA,IACxK;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,CAAC;AAEhB,SACE,qBAAC,MAAM,UAAN,EACC,UAAA;AAAA,IAAA,oBAAC,OAAA,EAAI,WAAU,sBAAqB,eAAe,WAAW,KAAW,GAAG,MAAO,UAAS;AAAA,IAC3F,OACC,oBAAC,OAAA,EAAI,WAAW,CAAC,cAAc,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAG,OAAO,EAAE,MAAM,KAAK,GAAG,KAAK,KAAK,EAAA,GAAK,SAAS,CAAC,MAAM,EAAE,mBAC1H,UAAA,MAAM,IAAI,CAAC,IAAI,MAAM;AACpB,UAAI,GAAG,SAAS,YAAa,4BAAQ,OAAA,EAAY,WAAU,qBAAb,CAA+B;AAC7E,UAAI,GAAG,SAAS,QAAS,QAAO,oBAAC,SAAY,WAAU,qBAAqB,UAAA,GAAG,MAAA,GAArC,CAA2C;AACrF,aACE,qBAAC,YAAe,WAAW,sBAAsB,GAAG,SAAS,8BAA8B,KAAK,SAAS,MAAM;AAAE,cAAA;AAAS,WAAG,YAAY,GAAG,SAAA;AAAA,MAAY,GACrJ,UAAA;AAAA,QAAA,GAAG;AAAA,QAAK,oBAAC,QAAA,EAAM,UAAA,GAAG,MAAA,CAAM;AAAA,QAAQ,GAAG,WAAW,oBAAC,QAAA,EAAK,WAAU,wBAAwB,UAAA,GAAG,UAAS,IAAU;AAAA,MAAA,EAAA,GADlG,CAEb;AAAA,IAEJ,CAAC,GACH,IACE;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action menu. Items support icons, shortcuts, danger styling, separators and labels.
|
|
3
|
+
*/
|
|
4
|
+
export interface MenuItem {
|
|
5
|
+
label?: React.ReactNode;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
shortcut?: string;
|
|
8
|
+
danger?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
onSelect?: () => void;
|
|
11
|
+
/** "separator" | "label" for structural rows. */
|
|
12
|
+
type?: "separator" | "label";
|
|
13
|
+
}
|
|
14
|
+
export interface DropdownMenuProps {
|
|
15
|
+
trigger: React.ReactNode;
|
|
16
|
+
items: MenuItem[];
|
|
17
|
+
/** @default "start" */
|
|
18
|
+
align?: "start" | "end";
|
|
19
|
+
}
|
|
20
|
+
export declare function DropdownMenu(props: DropdownMenuProps): JSX.Element;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useCallback, useEffect } from "react";
|
|
3
|
+
const AX_MENU_CSS = `
|
|
4
|
+
.ax-menu { position: relative; display: inline-flex; }
|
|
5
|
+
.ax-menu__panel {
|
|
6
|
+
position: absolute; z-index: 60; min-width: 200px; top: calc(100% + 6px);
|
|
7
|
+
background: var(--surface-panel); border: 1px solid var(--border-strong);
|
|
8
|
+
border-radius: var(--radius-3); box-shadow: var(--shadow-2); padding: var(--space-1);
|
|
9
|
+
animation: ax-menu-in var(--dur-2) var(--ease-out);
|
|
10
|
+
}
|
|
11
|
+
.ax-menu__panel--end { right: 0; }
|
|
12
|
+
.ax-menu__panel--start { left: 0; }
|
|
13
|
+
.ax-menu__item {
|
|
14
|
+
display: flex; align-items: center; gap: 10px; width: 100%;
|
|
15
|
+
appearance: none; background: none; border: none; text-align: left; cursor: pointer;
|
|
16
|
+
padding: 7px 10px; border-radius: var(--radius-2); color: var(--text-body);
|
|
17
|
+
font-family: var(--font-body); font-size: var(--text-sm);
|
|
18
|
+
transition: background var(--dur-1) var(--ease-out);
|
|
19
|
+
}
|
|
20
|
+
.ax-menu__item:hover { background: var(--surface-raised); }
|
|
21
|
+
.ax-menu__item:focus-visible { outline: none; background: var(--surface-raised); }
|
|
22
|
+
.ax-menu__item--danger { color: var(--danger); }
|
|
23
|
+
.ax-menu__item:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
24
|
+
.ax-menu__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }
|
|
25
|
+
.ax-menu__item--danger svg { color: var(--danger); }
|
|
26
|
+
.ax-menu__shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); letter-spacing: 0.04em; }
|
|
27
|
+
.ax-menu__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }
|
|
28
|
+
.ax-menu__sep { height: 1px; background: var(--border-default); margin: var(--space-1) 0; }
|
|
29
|
+
@keyframes ax-menu-in { from { opacity: 0; transform: translateY(-4px); } }
|
|
30
|
+
@media (prefers-reduced-motion: reduce) { .ax-menu__panel { animation: none; } }
|
|
31
|
+
`;
|
|
32
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-menu-css")) {
|
|
33
|
+
const s = document.createElement("style");
|
|
34
|
+
s.id = "ax-menu-css";
|
|
35
|
+
s.textContent = AX_MENU_CSS;
|
|
36
|
+
document.head.appendChild(s);
|
|
37
|
+
}
|
|
38
|
+
function DropdownMenu({ trigger, items = [], align = "start", className = "", ...rest }) {
|
|
39
|
+
const [open, setOpen] = useState(false);
|
|
40
|
+
const ref = useRef(null);
|
|
41
|
+
const onDoc = useCallback((e) => {
|
|
42
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
43
|
+
}, []);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (open) {
|
|
46
|
+
document.addEventListener("mousedown", onDoc);
|
|
47
|
+
const onKey = (e) => {
|
|
48
|
+
if (e.key === "Escape") setOpen(false);
|
|
49
|
+
};
|
|
50
|
+
document.addEventListener("keydown", onKey);
|
|
51
|
+
return () => {
|
|
52
|
+
document.removeEventListener("mousedown", onDoc);
|
|
53
|
+
document.removeEventListener("keydown", onKey);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}, [open, onDoc]);
|
|
57
|
+
return /* @__PURE__ */ jsxs("span", { className: ["ax-menu", className].filter(Boolean).join(" "), ref, ...rest, children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", { onClick: () => setOpen((o) => !o), children: trigger }),
|
|
59
|
+
open ? /* @__PURE__ */ jsx("div", { className: "ax-menu__panel ax-menu__panel--" + align, role: "menu", children: items.map((it, i) => {
|
|
60
|
+
if (it.type === "separator") return /* @__PURE__ */ jsx("div", { className: "ax-menu__sep" }, i);
|
|
61
|
+
if (it.type === "label") return /* @__PURE__ */ jsx("div", { className: "ax-menu__label", children: it.label }, i);
|
|
62
|
+
return /* @__PURE__ */ jsxs(
|
|
63
|
+
"button",
|
|
64
|
+
{
|
|
65
|
+
role: "menuitem",
|
|
66
|
+
disabled: it.disabled,
|
|
67
|
+
className: "ax-menu__item" + (it.danger ? " ax-menu__item--danger" : ""),
|
|
68
|
+
onClick: () => {
|
|
69
|
+
setOpen(false);
|
|
70
|
+
it.onSelect && it.onSelect();
|
|
71
|
+
},
|
|
72
|
+
children: [
|
|
73
|
+
it.icon,
|
|
74
|
+
/* @__PURE__ */ jsx("span", { children: it.label }),
|
|
75
|
+
it.shortcut ? /* @__PURE__ */ jsx("span", { className: "ax-menu__shortcut", children: it.shortcut }) : null
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
i
|
|
79
|
+
);
|
|
80
|
+
}) }) : null
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
DropdownMenu
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=DropdownMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DropdownMenu.js","sources":["../../../src/components/overlay/DropdownMenu.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\n\nconst AX_MENU_CSS = `\n.ax-menu { position: relative; display: inline-flex; }\n.ax-menu__panel {\n position: absolute; z-index: 60; min-width: 200px; top: calc(100% + 6px);\n background: var(--surface-panel); border: 1px solid var(--border-strong);\n border-radius: var(--radius-3); box-shadow: var(--shadow-2); padding: var(--space-1);\n animation: ax-menu-in var(--dur-2) var(--ease-out);\n}\n.ax-menu__panel--end { right: 0; }\n.ax-menu__panel--start { left: 0; }\n.ax-menu__item {\n display: flex; align-items: center; gap: 10px; width: 100%;\n appearance: none; background: none; border: none; text-align: left; cursor: pointer;\n padding: 7px 10px; border-radius: var(--radius-2); color: var(--text-body);\n font-family: var(--font-body); font-size: var(--text-sm);\n transition: background var(--dur-1) var(--ease-out);\n}\n.ax-menu__item:hover { background: var(--surface-raised); }\n.ax-menu__item:focus-visible { outline: none; background: var(--surface-raised); }\n.ax-menu__item--danger { color: var(--danger); }\n.ax-menu__item:disabled { opacity: 0.4; cursor: not-allowed; }\n.ax-menu__item svg { width: 15px; height: 15px; flex: none; color: var(--text-faint); }\n.ax-menu__item--danger svg { color: var(--danger); }\n.ax-menu__shortcut { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); letter-spacing: 0.04em; }\n.ax-menu__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }\n.ax-menu__sep { height: 1px; background: var(--border-default); margin: var(--space-1) 0; }\n@keyframes ax-menu-in { from { opacity: 0; transform: translateY(-4px); } }\n@media (prefers-reduced-motion: reduce) { .ax-menu__panel { animation: none; } }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-menu-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-menu-css\";\n s.textContent = AX_MENU_CSS;\n document.head.appendChild(s);\n}\n\nexport function DropdownMenu({ trigger, items = [], align = \"start\", className = \"\", ...rest }) {\n const [open, setOpen] = useState(false);\n const ref = useRef(null);\n\n const onDoc = useCallback((e) => {\n if (ref.current && !ref.current.contains(e.target)) setOpen(false);\n }, []);\n\n useEffect(() => {\n if (open) {\n document.addEventListener(\"mousedown\", onDoc);\n const onKey = (e) => { if (e.key === \"Escape\") setOpen(false); };\n document.addEventListener(\"keydown\", onKey);\n return () => { document.removeEventListener(\"mousedown\", onDoc); document.removeEventListener(\"keydown\", onKey); };\n }\n }, [open, onDoc]);\n\n return (\n <span className={[\"ax-menu\", className].filter(Boolean).join(\" \")} ref={ref} {...rest}>\n <span onClick={() => setOpen((o) => !o)}>{trigger}</span>\n {open ? (\n <div className={\"ax-menu__panel ax-menu__panel--\" + align} role=\"menu\">\n {items.map((it, i) => {\n if (it.type === \"separator\") return <div key={i} className=\"ax-menu__sep\"></div>;\n if (it.type === \"label\") return <div key={i} className=\"ax-menu__label\">{it.label}</div>;\n return (\n <button\n key={i}\n role=\"menuitem\"\n disabled={it.disabled}\n className={\"ax-menu__item\" + (it.danger ? \" ax-menu__item--danger\" : \"\")}\n onClick={() => { setOpen(false); it.onSelect && it.onSelect(); }}\n >\n {it.icon}\n <span>{it.label}</span>\n {it.shortcut ? <span className=\"ax-menu__shortcut\">{it.shortcut}</span> : null}\n </button>\n );\n })}\n </div>\n ) : null}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BpB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,aAAa,GAAG;AAC9E,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,aAAa,EAAE,SAAS,QAAQ,IAAI,QAAQ,SAAS,YAAY,IAAI,GAAG,QAAQ;AAC9F,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,MAAM,OAAO,IAAI;AAEvB,QAAM,QAAQ,YAAY,CAAC,MAAM;AAC/B,QAAI,IAAI,WAAW,CAAC,IAAI,QAAQ,SAAS,EAAE,MAAM,EAAG,SAAQ,KAAK;AAAA,EACnE,GAAG,CAAA,CAAE;AAEL,YAAU,MAAM;AACd,QAAI,MAAM;AACR,eAAS,iBAAiB,aAAa,KAAK;AAC5C,YAAM,QAAQ,CAAC,MAAM;AAAE,YAAI,EAAE,QAAQ,SAAU,SAAQ,KAAK;AAAA,MAAG;AAC/D,eAAS,iBAAiB,WAAW,KAAK;AAC1C,aAAO,MAAM;AAAE,iBAAS,oBAAoB,aAAa,KAAK;AAAG,iBAAS,oBAAoB,WAAW,KAAK;AAAA,MAAG;AAAA,IACnH;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,CAAC;AAEhB,SACE,qBAAC,QAAA,EAAK,WAAW,CAAC,WAAW,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAG,KAAW,GAAG,MAC/E,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAI,UAAA,QAAA,CAAQ;AAAA,IACjD,OACC,oBAAC,OAAA,EAAI,WAAW,oCAAoC,OAAO,MAAK,QAC7D,UAAA,MAAM,IAAI,CAAC,IAAI,MAAM;AACpB,UAAI,GAAG,SAAS,YAAa,4BAAQ,OAAA,EAAY,WAAU,kBAAb,CAA4B;AAC1E,UAAI,GAAG,SAAS,QAAS,QAAO,oBAAC,SAAY,WAAU,kBAAkB,UAAA,GAAG,MAAA,GAAlC,CAAwC;AAClF,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,MAAK;AAAA,UACL,UAAU,GAAG;AAAA,UACb,WAAW,mBAAmB,GAAG,SAAS,2BAA2B;AAAA,UACrE,SAAS,MAAM;AAAE,oBAAQ,KAAK;AAAG,eAAG,YAAY,GAAG,SAAA;AAAA,UAAY;AAAA,UAE9D,UAAA;AAAA,YAAA,GAAG;AAAA,YACJ,oBAAC,QAAA,EAAM,UAAA,GAAG,MAAA,CAAM;AAAA,YACf,GAAG,WAAW,oBAAC,QAAA,EAAK,WAAU,qBAAqB,UAAA,GAAG,UAAS,IAAU;AAAA,UAAA;AAAA,QAAA;AAAA,QARrE;AAAA,MAAA;AAAA,IAWX,CAAC,GACH,IACE;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Rich hover preview card (open/close delays). For non-essential supplementary info. */
|
|
2
|
+
export interface HoverCardProps { trigger: React.ReactNode; side?: "top" | "bottom"; openDelay?: number; closeDelay?: number; children?: React.ReactNode; }
|
|
3
|
+
export declare function HoverCard(props: HoverCardProps): JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from "react";
|
|
3
|
+
const AX_HOVERCARD_CSS = `
|
|
4
|
+
.ax-hovercard { position: relative; display: inline-flex; }
|
|
5
|
+
.ax-hovercard__trigger { border-bottom: 1px dashed var(--border-strong); cursor: help; }
|
|
6
|
+
.ax-hovercard__panel {
|
|
7
|
+
position: absolute; z-index: 60; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
|
|
8
|
+
width: 280px; padding: var(--space-4); pointer-events: none;
|
|
9
|
+
background: var(--surface-panel); border: 1px solid var(--border-strong);
|
|
10
|
+
border-radius: var(--radius-3); box-shadow: var(--shadow-2);
|
|
11
|
+
opacity: 0; transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
|
|
12
|
+
}
|
|
13
|
+
.ax-hovercard__panel--bottom { bottom: auto; top: calc(100% + 8px); }
|
|
14
|
+
.ax-hovercard--open .ax-hovercard__panel { opacity: 1; pointer-events: auto; }
|
|
15
|
+
`;
|
|
16
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-hovercard-css")) {
|
|
17
|
+
const s = document.createElement("style");
|
|
18
|
+
s.id = "ax-hovercard-css";
|
|
19
|
+
s.textContent = AX_HOVERCARD_CSS;
|
|
20
|
+
document.head.appendChild(s);
|
|
21
|
+
}
|
|
22
|
+
function HoverCard({ trigger, children, side = "top", openDelay = 200, closeDelay = 120, className = "", ...rest }) {
|
|
23
|
+
const [open, setOpen] = useState(false);
|
|
24
|
+
const timer = useRef(null);
|
|
25
|
+
const enter = () => {
|
|
26
|
+
clearTimeout(timer.current);
|
|
27
|
+
timer.current = setTimeout(() => setOpen(true), openDelay);
|
|
28
|
+
};
|
|
29
|
+
const leave = () => {
|
|
30
|
+
clearTimeout(timer.current);
|
|
31
|
+
timer.current = setTimeout(() => setOpen(false), closeDelay);
|
|
32
|
+
};
|
|
33
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
34
|
+
return /* @__PURE__ */ jsxs(
|
|
35
|
+
"span",
|
|
36
|
+
{
|
|
37
|
+
className: ["ax-hovercard", open ? "ax-hovercard--open" : "", className].filter(Boolean).join(" "),
|
|
38
|
+
onMouseEnter: enter,
|
|
39
|
+
onMouseLeave: leave,
|
|
40
|
+
onFocus: enter,
|
|
41
|
+
onBlur: leave,
|
|
42
|
+
...rest,
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsx("span", { className: "ax-hovercard__trigger", children: trigger }),
|
|
45
|
+
/* @__PURE__ */ jsx("span", { className: "ax-hovercard__panel" + (side === "bottom" ? " ax-hovercard__panel--bottom" : ""), children })
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
HoverCard
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=HoverCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HoverCard.js","sources":["../../../src/components/overlay/HoverCard.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\n\nconst AX_HOVERCARD_CSS = `\n.ax-hovercard { position: relative; display: inline-flex; }\n.ax-hovercard__trigger { border-bottom: 1px dashed var(--border-strong); cursor: help; }\n.ax-hovercard__panel {\n position: absolute; z-index: 60; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);\n width: 280px; padding: var(--space-4); pointer-events: none;\n background: var(--surface-panel); border: 1px solid var(--border-strong);\n border-radius: var(--radius-3); box-shadow: var(--shadow-2);\n opacity: 0; transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);\n}\n.ax-hovercard__panel--bottom { bottom: auto; top: calc(100% + 8px); }\n.ax-hovercard--open .ax-hovercard__panel { opacity: 1; pointer-events: auto; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-hovercard-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-hovercard-css\";\n s.textContent = AX_HOVERCARD_CSS;\n document.head.appendChild(s);\n}\n\nexport function HoverCard({ trigger, children, side = \"top\", openDelay = 200, closeDelay = 120, className = \"\", ...rest }) {\n const [open, setOpen] = useState(false);\n const timer = useRef(null);\n const enter = () => { clearTimeout(timer.current); timer.current = setTimeout(() => setOpen(true), openDelay); };\n const leave = () => { clearTimeout(timer.current); timer.current = setTimeout(() => setOpen(false), closeDelay); };\n useEffect(() => () => clearTimeout(timer.current), []);\n return (\n <span\n className={[\"ax-hovercard\", open ? \"ax-hovercard--open\" : \"\", className].filter(Boolean).join(\" \")}\n onMouseEnter={enter} onMouseLeave={leave} onFocus={enter} onBlur={leave}\n {...rest}\n >\n <span className=\"ax-hovercard__trigger\">{trigger}</span>\n <span className={\"ax-hovercard__panel\" + (side === \"bottom\" ? \" ax-hovercard__panel--bottom\" : \"\")}>{children}</span>\n </span>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAczB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU,EAAE,SAAS,UAAU,OAAO,OAAO,YAAY,KAAK,aAAa,KAAK,YAAY,IAAI,GAAG,QAAQ;AACzH,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,QAAQ,OAAO,IAAI;AACzB,QAAM,QAAQ,MAAM;AAAE,iBAAa,MAAM,OAAO;AAAG,UAAM,UAAU,WAAW,MAAM,QAAQ,IAAI,GAAG,SAAS;AAAA,EAAG;AAC/G,QAAM,QAAQ,MAAM;AAAE,iBAAa,MAAM,OAAO;AAAG,UAAM,UAAU,WAAW,MAAM,QAAQ,KAAK,GAAG,UAAU;AAAA,EAAG;AACjH,YAAU,MAAM,MAAM,aAAa,MAAM,OAAO,GAAG,CAAA,CAAE;AACrD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,CAAC,gBAAgB,OAAO,uBAAuB,IAAI,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,MACjG,cAAc;AAAA,MAAO,cAAc;AAAA,MAAO,SAAS;AAAA,MAAO,QAAQ;AAAA,MACjE,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,yBAAyB,UAAA,SAAQ;AAAA,QACjD,oBAAC,UAAK,WAAW,yBAAyB,SAAS,WAAW,iCAAiC,KAAM,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGpH;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Desktop-style menubar; hover to move between open menus. */
|
|
2
|
+
export interface MenubarMenu { label: string; items: Array<{ label?: React.ReactNode; shortcut?: string; onSelect?: () => void; type?: "separator" }>; }
|
|
3
|
+
export interface MenubarProps { menus: MenubarMenu[]; }
|
|
4
|
+
export declare function Menubar(props: MenubarProps): JSX.Element;
|