eidotter 0.36.1 → 0.37.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/README.md +19 -0
- package/dist/components/AIText/components/AIText.d.ts +0 -1
- package/dist/components/AIText/components/AIText.js +23 -0
- package/dist/components/AIText/components/index.d.ts +2 -2
- package/dist/components/AIText/components/index.js +1 -0
- package/dist/components/AIText/index.d.ts +2 -2
- package/dist/components/AIText/index.js +1 -0
- package/dist/components/Accordion/components/AccordionFill.d.ts +0 -1
- package/dist/components/Accordion/components/AccordionFill.js +12 -0
- package/dist/components/Accordion/components/Section.d.ts +0 -1
- package/dist/components/Accordion/components/Section.js +22 -0
- package/dist/components/Accordion/components/index.d.ts +4 -4
- package/dist/components/Accordion/components/index.js +2 -0
- package/dist/components/Accordion/index.d.ts +1 -1
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/Alert/components/Alert.d.ts +0 -1
- package/dist/components/Alert/components/Alert.js +51 -0
- package/dist/components/Alert/components/index.d.ts +2 -2
- package/dist/components/Alert/components/index.js +1 -0
- package/dist/components/Alert/index.d.ts +1 -1
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Badge/components/Badge.d.ts +0 -1
- package/dist/components/Badge/components/Badge.js +31 -0
- package/dist/components/Badge/components/index.d.ts +2 -2
- package/dist/components/Badge/components/index.js +1 -0
- package/dist/components/Badge/index.d.ts +2 -2
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Brand/components/BrandLockup.js +14 -0
- package/dist/components/Brand/components/Logo.d.ts +0 -1
- package/dist/components/Brand/components/Logo.js +22 -0
- package/dist/components/Brand/components/Wordmark.d.ts +0 -1
- package/dist/components/Brand/components/Wordmark.js +13 -0
- package/dist/components/Brand/components/index.d.ts +6 -6
- package/dist/components/Brand/components/index.js +3 -0
- package/dist/components/Brand/index.d.ts +1 -1
- package/dist/components/Brand/index.js +1 -0
- package/dist/components/Breadcrumb/components/Breadcrumb.d.ts +0 -1
- package/dist/components/Breadcrumb/components/Breadcrumb.js +29 -0
- package/dist/components/Breadcrumb/components/index.d.ts +2 -2
- package/dist/components/Breadcrumb/components/index.js +1 -0
- package/dist/components/Breadcrumb/index.d.ts +2 -2
- package/dist/components/Breadcrumb/index.js +1 -0
- package/dist/components/Button/components/Button.d.ts +0 -2
- package/dist/components/Button/components/Button.js +49 -0
- package/dist/components/Button/components/index.d.ts +2 -2
- package/dist/components/Button/components/index.js +1 -0
- package/dist/components/Button/index.d.ts +2 -2
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Card/components/Card.d.ts +0 -1
- package/dist/components/Card/components/Card.js +16 -0
- package/dist/components/Card/components/index.d.ts +2 -2
- package/dist/components/Card/components/index.js +1 -0
- package/dist/components/Card/index.d.ts +2 -2
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Chat/components/ChatContainer.d.ts +1 -1
- package/dist/components/Chat/components/ChatContainer.js +20 -0
- package/dist/components/Chat/components/ChatHistory.d.ts +0 -1
- package/dist/components/Chat/components/ChatHistory.js +27 -0
- package/dist/components/Chat/components/ChatInput.d.ts +0 -2
- package/dist/components/Chat/components/ChatInput.js +37 -0
- package/dist/components/Chat/components/ChatMessage.d.ts +0 -2
- package/dist/components/Chat/components/ChatMessage.js +18 -0
- package/dist/components/Chat/components/index.d.ts +8 -8
- package/dist/components/Chat/components/index.js +4 -0
- package/dist/components/Chat/index.d.ts +2 -2
- package/dist/components/Chat/index.js +1 -0
- package/dist/components/Checkbox/components/Checkbox.d.ts +0 -2
- package/dist/components/Checkbox/components/Checkbox.js +11 -0
- package/dist/components/Checkbox/components/index.d.ts +2 -2
- package/dist/components/Checkbox/components/index.js +1 -0
- package/dist/components/Checkbox/index.d.ts +2 -2
- package/dist/components/Checkbox/index.js +1 -0
- package/dist/components/ChecklistRow/components/ChecklistRow.js +18 -0
- package/dist/components/ChecklistRow/components/index.d.ts +2 -2
- package/dist/components/ChecklistRow/components/index.js +1 -0
- package/dist/components/ChecklistRow/index.d.ts +2 -2
- package/dist/components/ChecklistRow/index.js +1 -0
- package/dist/components/CmdPalette/components/CmdPalette.d.ts +0 -2
- package/dist/components/CmdPalette/components/CmdPalette.js +169 -0
- package/dist/components/CmdPalette/components/index.d.ts +2 -2
- package/dist/components/CmdPalette/components/index.js +1 -0
- package/dist/components/CmdPalette/index.d.ts +2 -2
- package/dist/components/CmdPalette/index.js +1 -0
- package/dist/components/CommandPrompt/components/CommandPrompt.d.ts +0 -2
- package/dist/components/CommandPrompt/components/CommandPrompt.js +34 -0
- package/dist/components/CommandPrompt/components/index.d.ts +2 -2
- package/dist/components/CommandPrompt/components/index.js +1 -0
- package/dist/components/CommandPrompt/index.d.ts +1 -1
- package/dist/components/CommandPrompt/index.js +1 -0
- package/dist/components/CopyButton/components/CopyButton.js +50 -0
- package/dist/components/CopyButton/components/index.d.ts +2 -2
- package/dist/components/CopyButton/components/index.js +1 -0
- package/dist/components/CopyButton/index.d.ts +2 -2
- package/dist/components/CopyButton/index.js +1 -0
- package/dist/components/DosFigure/components/DosFigure.d.ts +0 -1
- package/dist/components/DosFigure/components/DosFigure.js +26 -0
- package/dist/components/DosFigure/components/index.d.ts +2 -2
- package/dist/components/DosFigure/components/index.js +1 -0
- package/dist/components/DosFigure/index.d.ts +2 -2
- package/dist/components/DosFigure/index.js +1 -0
- package/dist/components/EmptyState/components/EmptyState.js +18 -0
- package/dist/components/EmptyState/components/index.d.ts +2 -2
- package/dist/components/EmptyState/components/index.js +1 -0
- package/dist/components/EmptyState/index.d.ts +2 -2
- package/dist/components/EmptyState/index.js +1 -0
- package/dist/components/FilterBar/components/FilterBar.d.ts +0 -1
- package/dist/components/FilterBar/components/FilterBar.js +120 -0
- package/dist/components/FilterBar/components/index.d.ts +2 -2
- package/dist/components/FilterBar/components/index.js +1 -0
- package/dist/components/FilterBar/index.d.ts +2 -2
- package/dist/components/FilterBar/index.js +1 -0
- package/dist/components/Footer/components/Footer.d.ts +0 -1
- package/dist/components/Footer/components/Footer.js +18 -0
- package/dist/components/Footer/components/index.d.ts +2 -2
- package/dist/components/Footer/components/index.js +1 -0
- package/dist/components/Footer/index.d.ts +2 -2
- package/dist/components/Footer/index.js +1 -0
- package/dist/components/Header/components/Header.d.ts +1 -2
- package/dist/components/Header/components/Header.js +13 -0
- package/dist/components/Header/components/index.d.ts +2 -2
- package/dist/components/Header/components/index.js +1 -0
- package/dist/components/Header/index.d.ts +2 -2
- package/dist/components/Header/index.js +1 -0
- package/dist/components/Icon/components/Icon.d.ts +0 -1
- package/dist/components/Icon/components/Icon.js +78 -0
- package/dist/components/Icon/components/index.d.ts +2 -2
- package/dist/components/Icon/components/index.js +1 -0
- package/dist/components/Icon/index.d.ts +1 -1
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/InlineExpand/components/InlineExpand.d.ts +0 -1
- package/dist/components/InlineExpand/components/InlineExpand.js +50 -0
- package/dist/components/InlineExpand/components/index.d.ts +2 -2
- package/dist/components/InlineExpand/components/index.js +1 -0
- package/dist/components/InlineExpand/index.d.ts +2 -2
- package/dist/components/InlineExpand/index.js +1 -0
- package/dist/components/InlineLink/components/InlineLink.d.ts +0 -1
- package/dist/components/InlineLink/components/InlineLink.js +61 -0
- package/dist/components/InlineLink/components/index.d.ts +2 -2
- package/dist/components/InlineLink/components/index.js +1 -0
- package/dist/components/InlineLink/index.d.ts +2 -2
- package/dist/components/InlineLink/index.js +1 -0
- package/dist/components/Input/components/Input.d.ts +0 -1
- package/dist/components/Input/components/Input.js +18 -0
- package/dist/components/Input/components/index.d.ts +2 -2
- package/dist/components/Input/components/index.js +1 -0
- package/dist/components/Input/index.d.ts +1 -1
- package/dist/components/Input/index.js +1 -0
- package/dist/components/LabeledProgress/components/LabeledProgress.d.ts +0 -1
- package/dist/components/LabeledProgress/components/LabeledProgress.js +16 -0
- package/dist/components/LabeledProgress/components/index.d.ts +2 -2
- package/dist/components/LabeledProgress/components/index.js +1 -0
- package/dist/components/LabeledProgress/index.d.ts +2 -2
- package/dist/components/LabeledProgress/index.js +1 -0
- package/dist/components/LedgerRow/components/LedgerRow.js +15 -0
- package/dist/components/LedgerRow/components/index.d.ts +2 -2
- package/dist/components/LedgerRow/components/index.js +1 -0
- package/dist/components/LedgerRow/index.d.ts +2 -2
- package/dist/components/LedgerRow/index.js +1 -0
- package/dist/components/LegalPage/components/LegalPage.d.ts +0 -1
- package/dist/components/LegalPage/components/LegalPage.js +11 -0
- package/dist/components/LegalPage/components/clauses.js +28 -0
- package/dist/components/LegalPage/components/index.d.ts +4 -4
- package/dist/components/LegalPage/components/index.js +2 -0
- package/dist/components/LegalPage/index.d.ts +2 -2
- package/dist/components/LegalPage/index.js +1 -0
- package/dist/components/Lightbox/components/Lightbox.d.ts +1 -3
- package/dist/components/Lightbox/components/Lightbox.js +97 -0
- package/dist/components/Lightbox/components/index.d.ts +2 -2
- package/dist/components/Lightbox/components/index.js +1 -0
- package/dist/components/Lightbox/index.d.ts +2 -2
- package/dist/components/Lightbox/index.js +1 -0
- package/dist/components/Modal/components/Modal.d.ts +0 -2
- package/dist/components/Modal/components/Modal.js +37 -0
- package/dist/components/Modal/components/index.d.ts +2 -2
- package/dist/components/Modal/components/index.js +1 -0
- package/dist/components/Modal/index.d.ts +2 -2
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/Nav/components/Nav.d.ts +0 -1
- package/dist/components/Nav/components/Nav.js +69 -0
- package/dist/components/Nav/components/index.d.ts +2 -2
- package/dist/components/Nav/components/index.js +1 -0
- package/dist/components/Nav/index.d.ts +2 -2
- package/dist/components/Nav/index.js +1 -0
- package/dist/components/Notification/components/Notification.d.ts +1 -2
- package/dist/components/Notification/components/Notification.js +34 -0
- package/dist/components/Notification/components/index.d.ts +2 -2
- package/dist/components/Notification/components/index.js +1 -0
- package/dist/components/Notification/index.d.ts +1 -1
- package/dist/components/Notification/index.js +1 -0
- package/dist/components/Progress/components/Progress.d.ts +0 -1
- package/dist/components/Progress/components/Progress.js +72 -0
- package/dist/components/Progress/components/index.d.ts +2 -2
- package/dist/components/Progress/components/index.js +1 -0
- package/dist/components/Progress/index.d.ts +2 -2
- package/dist/components/Progress/index.js +1 -0
- package/dist/components/RetroEffects/components/RetroEffects.d.ts +0 -1
- package/dist/components/RetroEffects/components/RetroEffects.js +163 -0
- package/dist/components/RetroEffects/components/index.d.ts +2 -2
- package/dist/components/RetroEffects/components/index.js +1 -0
- package/dist/components/RetroEffects/index.d.ts +2 -2
- package/dist/components/RetroEffects/index.js +1 -0
- package/dist/components/SectionHeading/components/SectionHeading.js +18 -0
- package/dist/components/SectionHeading/components/index.d.ts +2 -2
- package/dist/components/SectionHeading/components/index.js +1 -0
- package/dist/components/SectionHeading/index.d.ts +2 -2
- package/dist/components/SectionHeading/index.js +1 -0
- package/dist/components/Select/components/Select.js +14 -0
- package/dist/components/Select/components/index.d.ts +2 -2
- package/dist/components/Select/components/index.js +1 -0
- package/dist/components/Select/index.d.ts +2 -2
- package/dist/components/Select/index.js +1 -0
- package/dist/components/Separator/components/Separator.d.ts +0 -1
- package/dist/components/Separator/components/Separator.js +11 -0
- package/dist/components/Separator/components/index.d.ts +2 -2
- package/dist/components/Separator/components/index.js +1 -0
- package/dist/components/Separator/index.d.ts +2 -2
- package/dist/components/Separator/index.js +1 -0
- package/dist/components/Skeleton/components/Skeleton.d.ts +0 -1
- package/dist/components/Skeleton/components/Skeleton.js +52 -0
- package/dist/components/Skeleton/components/index.d.ts +2 -2
- package/dist/components/Skeleton/components/index.js +1 -0
- package/dist/components/Skeleton/index.d.ts +2 -2
- package/dist/components/Skeleton/index.js +1 -0
- package/dist/components/Stat/components/Stat.d.ts +0 -1
- package/dist/components/Stat/components/Stat.js +42 -0
- package/dist/components/Stat/components/index.d.ts +2 -2
- package/dist/components/Stat/components/index.js +1 -0
- package/dist/components/Stat/index.d.ts +2 -2
- package/dist/components/Stat/index.js +1 -0
- package/dist/components/Switch/components/Switch.d.ts +0 -1
- package/dist/components/Switch/components/Switch.js +11 -0
- package/dist/components/Switch/components/index.d.ts +2 -2
- package/dist/components/Switch/components/index.js +1 -0
- package/dist/components/Switch/index.d.ts +2 -2
- package/dist/components/Switch/index.js +1 -0
- package/dist/components/Tabs/components/Tabs.d.ts +0 -1
- package/dist/components/Tabs/components/Tabs.js +54 -0
- package/dist/components/Tabs/components/index.d.ts +2 -2
- package/dist/components/Tabs/components/index.js +1 -0
- package/dist/components/Tabs/index.d.ts +2 -2
- package/dist/components/Tabs/index.js +1 -0
- package/dist/components/Tag/components/Tag.d.ts +0 -1
- package/dist/components/Tag/components/Tag.js +46 -0
- package/dist/components/Tag/components/TagGroup.js +15 -0
- package/dist/components/Tag/components/index.d.ts +4 -4
- package/dist/components/Tag/components/index.js +2 -0
- package/dist/components/Tag/index.d.ts +2 -2
- package/dist/components/Tag/index.js +1 -0
- package/dist/components/Terminal/components/Terminal.d.ts +0 -2
- package/dist/components/Terminal/components/Terminal.js +43 -0
- package/dist/components/Terminal/components/index.d.ts +2 -2
- package/dist/components/Terminal/components/index.js +1 -0
- package/dist/components/Terminal/index.d.ts +1 -1
- package/dist/components/Terminal/index.js +1 -0
- package/dist/components/TextScramble/components/TextScramble.d.ts +0 -1
- package/dist/components/TextScramble/components/TextScramble.js +14 -0
- package/dist/components/TextScramble/components/index.d.ts +2 -2
- package/dist/components/TextScramble/components/index.js +1 -0
- package/dist/components/TextScramble/index.d.ts +1 -1
- package/dist/components/TextScramble/index.js +1 -0
- package/dist/components/TimelineContainer/components/MasterDetailLayout.d.ts +1 -3
- package/dist/components/TimelineContainer/components/MasterDetailLayout.js +77 -0
- package/dist/components/TimelineContainer/components/TimelineAxis.d.ts +0 -1
- package/dist/components/TimelineContainer/components/TimelineAxis.js +8 -0
- package/dist/components/TimelineContainer/components/TimelineContainer.d.ts +1 -3
- package/dist/components/TimelineContainer/components/TimelineContainer.js +218 -0
- package/dist/components/TimelineContainer/components/TimelineContent.d.ts +1 -1
- package/dist/components/TimelineContainer/components/TimelineContent.js +23 -0
- package/dist/components/TimelineContainer/components/TimelineEntryCard.d.ts +1 -2
- package/dist/components/TimelineContainer/components/TimelineEntryCard.js +50 -0
- package/dist/components/TimelineContainer/components/ZoomControls.d.ts +2 -3
- package/dist/components/TimelineContainer/components/ZoomControls.js +16 -0
- package/dist/components/TimelineContainer/components/index.d.ts +5 -5
- package/dist/components/TimelineContainer/components/index.js +2 -0
- package/dist/components/TimelineContainer/components/timelineUtils.d.ts +1 -1
- package/dist/components/TimelineContainer/components/timelineUtils.js +185 -0
- package/dist/components/TimelineContainer/components/types.js +7 -0
- package/dist/components/TimelineContainer/components/useDrillDown.d.ts +1 -1
- package/dist/components/TimelineContainer/components/useDrillDown.js +83 -0
- package/dist/components/TimelineContainer/components/useSelection.js +51 -0
- package/dist/components/TimelineContainer/components/useZoom.d.ts +1 -1
- package/dist/components/TimelineContainer/components/useZoom.js +54 -0
- package/dist/components/TimelineContainer/components/variants/TimelineEntryCardGallery.d.ts +1 -2
- package/dist/components/TimelineContainer/components/variants/TimelineEntryCardGallery.js +67 -0
- package/dist/components/TimelineContainer/components/variants/TimelineEntryCardImage.d.ts +1 -2
- package/dist/components/TimelineContainer/components/variants/TimelineEntryCardImage.js +31 -0
- package/dist/components/TimelineContainer/components/views/DayView.d.ts +1 -1
- package/dist/components/TimelineContainer/components/views/DayView.js +20 -0
- package/dist/components/TimelineContainer/components/views/HourView.d.ts +1 -1
- package/dist/components/TimelineContainer/components/views/HourView.js +22 -0
- package/dist/components/TimelineContainer/components/views/MonthView.d.ts +1 -1
- package/dist/components/TimelineContainer/components/views/MonthView.js +18 -0
- package/dist/components/TimelineContainer/components/views/YearView.d.ts +1 -1
- package/dist/components/TimelineContainer/components/views/YearView.js +13 -0
- package/dist/components/TimelineContainer/components/views/index.d.ts +4 -4
- package/dist/components/TimelineContainer/components/views/index.js +4 -0
- package/dist/components/TimelineContainer/index.d.ts +3 -3
- package/dist/components/TimelineContainer/index.js +2 -0
- package/dist/components/TimelineNode/components/TimelineNode.d.ts +0 -1
- package/dist/components/TimelineNode/components/TimelineNode.js +49 -0
- package/dist/components/TimelineNode/components/index.d.ts +2 -2
- package/dist/components/TimelineNode/components/index.js +1 -0
- package/dist/components/TimelineNode/index.d.ts +2 -2
- package/dist/components/TimelineNode/index.js +1 -0
- package/dist/components/registry.js +247 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useAnimatedDismiss.d.ts +15 -0
- package/dist/hooks/useAnimatedDismiss.js +29 -0
- package/dist/hooks/useTextScramble.d.ts +21 -0
- package/dist/hooks/useTextScramble.js +91 -0
- package/dist/hooks/useTextScramble.test.d.ts +1 -0
- package/dist/hooks/useThemePortal.d.ts +12 -0
- package/dist/hooks/useThemePortal.js +62 -0
- package/dist/hooks/useThemePortal.test.d.ts +1 -0
- package/dist/utils/cn.d.ts +9 -0
- package/dist/utils/cn.js +12 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/isSafeHref.d.ts +1 -0
- package/dist/utils/isSafeHref.js +22 -0
- package/dist/utils/isSafeUrl.d.ts +8 -0
- package/dist/utils/isSafeUrl.js +18 -0
- package/dist/utils/isSafeUrl.test.d.ts +1 -0
- package/dist/utils/prefersReducedMotion.d.ts +5 -0
- package/dist/utils/prefersReducedMotion.js +8 -0
- package/package.json +9 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { ChatHistory } from './ChatHistory.js';
|
|
5
|
+
import { ChatInput } from './ChatInput.js';
|
|
6
|
+
/**
|
|
7
|
+
* Complete DOS-themed chat interface composing ChatHistory and ChatInput.
|
|
8
|
+
*
|
|
9
|
+
* Designed to be placed inside a Terminal component for the full DOS window
|
|
10
|
+
* experience, but works standalone too.
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Terminal title="ADOS Chat">
|
|
14
|
+
* <ChatContainer messages={messages} onSend={send} isStreaming={loading} />
|
|
15
|
+
* </Terminal>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export const ChatContainer = ({ messages, onSend, isStreaming = false, inputPrompt, userPrefix, assistantPrefix, placeholder, disabled = false, className, ...props }) => {
|
|
19
|
+
return (_jsxs("div", { className: cn('flex flex-col h-full min-h-0', className), ...props, children: [_jsx(ChatHistory, { className: "flex-1 min-h-0", messages: messages, isStreaming: isStreaming, userPrefix: userPrefix, assistantPrefix: assistantPrefix }), _jsx(ChatInput, { className: "shrink-0", onSend: onSend, prompt: inputPrompt, placeholder: placeholder, disabled: disabled })] }));
|
|
20
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useEffect } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
import { ChatMessage } from './ChatMessage.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scrollable chat message history with auto-scroll and screen reader support.
|
|
8
|
+
*
|
|
9
|
+
* Uses `role="log"` for accessible announcement of new messages.
|
|
10
|
+
* Follows the data-driven list pattern (TimelineList precedent).
|
|
11
|
+
*/
|
|
12
|
+
export const ChatHistory = ({ messages, isStreaming = false, userPrefix, assistantPrefix, className, ...props }) => {
|
|
13
|
+
const bottomRef = useRef(null);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
bottomRef.current?.scrollIntoView?.({ behavior: 'smooth' });
|
|
16
|
+
}, [messages.length, isStreaming]);
|
|
17
|
+
const classes = cn('flex-1 overflow-y-auto font-dos p-2 min-h-0', 'eidotter-chat-history', className);
|
|
18
|
+
if (messages.length === 0) {
|
|
19
|
+
return (_jsx("div", { className: classes, role: "log", "aria-live": "polite", tabIndex: 0, ...props, children: _jsx("div", { className: "flex items-center justify-center h-full min-h-16", children: _jsx("span", { className: "text-dos-text-muted font-dos text-dos-text-md", children: "Awaiting input..." }) }) }));
|
|
20
|
+
}
|
|
21
|
+
return (_jsx("div", { className: classes, role: "log", "aria-live": "polite", tabIndex: 0, ...props, children: _jsxs("div", { className: "flex flex-col", children: [messages.map((msg, index) => {
|
|
22
|
+
const isLastAssistant = isStreaming &&
|
|
23
|
+
msg.role === 'assistant' &&
|
|
24
|
+
index === messages.length - 1;
|
|
25
|
+
return (_jsx(ChatMessage, { role: msg.role, content: msg.content, isStreaming: isLastAssistant, userPrefix: userPrefix, assistantPrefix: assistantPrefix }, msg.id));
|
|
26
|
+
}), _jsx("div", { ref: bottomRef })] }) }));
|
|
27
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useLayoutEffect } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
/**
|
|
6
|
+
* DOS-styled multiline chat input with Enter-to-send and Shift+Enter for newlines.
|
|
7
|
+
*
|
|
8
|
+
* Auto-grows as the user types, up to a max height. Shows a blinking cursor
|
|
9
|
+
* when not focused.
|
|
10
|
+
*/
|
|
11
|
+
export const ChatInput = ({ onSend, prompt = '>', placeholder, disabled = false, className, ...props }) => {
|
|
12
|
+
const [value, setValue] = useState('');
|
|
13
|
+
const textareaRef = useRef(null);
|
|
14
|
+
useLayoutEffect(() => {
|
|
15
|
+
const textarea = textareaRef.current;
|
|
16
|
+
if (!textarea)
|
|
17
|
+
return;
|
|
18
|
+
textarea.style.height = 'auto';
|
|
19
|
+
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
20
|
+
}, [value]);
|
|
21
|
+
const handleKeyDown = (e) => {
|
|
22
|
+
if (e.key === 'Enter' && !e.shiftKey && !disabled) {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const trimmed = value.trim();
|
|
25
|
+
if (trimmed) {
|
|
26
|
+
onSend(trimmed);
|
|
27
|
+
setValue('');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const handleContainerClick = () => {
|
|
32
|
+
if (!disabled && textareaRef.current) {
|
|
33
|
+
textareaRef.current.focus();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return (_jsxs("div", { className: cn('flex items-start font-dos text-dos-text-md p-2 cursor-text', 'text-dos-text-brand', 'eidotter-chat-input', disabled && 'eidotter-chat-input--disabled', className), onClick: handleContainerClick, ...props, children: [_jsx("span", { className: "text-dos-text-brand mr-2 mt-0.5 whitespace-nowrap select-none", "aria-hidden": "true", children: prompt }), _jsxs("div", { className: "flex items-start flex-1 min-w-0", children: [_jsx("textarea", { ref: textareaRef, className: "eidotter-chat-input__textarea", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1, "aria-label": "Chat input" }), _jsx("span", { className: "eidotter-chat-input__cursor", "aria-hidden": "true", children: "\u2588" })] })] }));
|
|
37
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../../utils/cn.js';
|
|
3
|
+
const roleClasses = {
|
|
4
|
+
user: 'eidotter-chat-message--user',
|
|
5
|
+
assistant: 'eidotter-chat-message--assistant',
|
|
6
|
+
system: 'eidotter-chat-message--system',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A single chat message rendered in DOS terminal style.
|
|
10
|
+
*
|
|
11
|
+
* User messages display with a `>` prefix, assistant messages with `C:\>`,
|
|
12
|
+
* and system messages appear dimmed. When `isStreaming` is true, a blinking
|
|
13
|
+
* block cursor appears after the content.
|
|
14
|
+
*/
|
|
15
|
+
export const ChatMessage = ({ role, content, isStreaming = false, userPrefix = '>', assistantPrefix = 'C:\\>', className, ...props }) => {
|
|
16
|
+
const prefix = role === 'user' ? userPrefix : role === 'assistant' ? assistantPrefix : '';
|
|
17
|
+
return (_jsxs("div", { className: cn('flex gap-2 font-dos text-dos-text-md leading-[1.4] py-1 whitespace-pre-wrap break-words', roleClasses[role], isStreaming && 'eidotter-chat-message--streaming', className), ...props, children: [prefix && (_jsx("span", { className: "shrink-0 select-none", "aria-hidden": "true", children: prefix })), _jsx("span", { className: "min-w-0", children: content }), isStreaming && (_jsx("span", { className: "eidotter-chat-message__cursor", "aria-hidden": "true", children: "\u2588" }))] }));
|
|
18
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { ChatMessage } from './ChatMessage';
|
|
2
|
-
export type { ChatMessageProps } from './ChatMessage';
|
|
3
|
-
export { ChatHistory } from './ChatHistory';
|
|
4
|
-
export type { ChatHistoryProps, ChatMessageEntry } from './ChatHistory';
|
|
5
|
-
export { ChatInput } from './ChatInput';
|
|
6
|
-
export type { ChatInputProps } from './ChatInput';
|
|
7
|
-
export { ChatContainer } from './ChatContainer';
|
|
8
|
-
export type { ChatContainerProps } from './ChatContainer';
|
|
1
|
+
export { ChatMessage } from './ChatMessage.js';
|
|
2
|
+
export type { ChatMessageProps } from './ChatMessage.js';
|
|
3
|
+
export { ChatHistory } from './ChatHistory.js';
|
|
4
|
+
export type { ChatHistoryProps, ChatMessageEntry } from './ChatHistory.js';
|
|
5
|
+
export { ChatInput } from './ChatInput.js';
|
|
6
|
+
export type { ChatInputProps } from './ChatInput.js';
|
|
7
|
+
export { ChatContainer } from './ChatContainer.js';
|
|
8
|
+
export type { ChatContainerProps } from './ChatContainer.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { ChatMessage, ChatHistory, ChatInput, ChatContainer } from './components';
|
|
2
|
-
export type { ChatMessageProps, ChatHistoryProps, ChatMessageEntry, ChatInputProps, ChatContainerProps, } from './components';
|
|
1
|
+
export { ChatMessage, ChatHistory, ChatInput, ChatContainer } from './components/index.js';
|
|
2
|
+
export type { ChatMessageProps, ChatHistoryProps, ChatMessageEntry, ChatInputProps, ChatContainerProps, } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChatMessage, ChatHistory, ChatInput, ChatContainer } from './components/index.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { Checkbox as AriaCheckbox } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
/**
|
|
7
|
+
* DOS-styled Checkbox with bracket text indicator [ ] / [X].
|
|
8
|
+
* Built on React Aria for accessible keyboard/focus handling.
|
|
9
|
+
*/
|
|
10
|
+
export const Checkbox = forwardRef(({ checked, defaultChecked, onChange, indeterminate = false, label, disabled = false, size = 'md', name, value, className, 'aria-label': ariaLabel, ...props }, ref) => (_jsx(AriaCheckbox, { ref: ref, isSelected: checked, defaultSelected: defaultChecked, isIndeterminate: indeterminate, onChange: onChange, isDisabled: disabled, name: name, value: value, "aria-label": ariaLabel || label, className: cn('inline-flex items-center gap-2 cursor-pointer select-none group', 'font-dos', size === 'sm' ? 'text-dos-text-xs' : 'text-dos-text-sm', 'eidotter-checkbox', disabled && 'opacity-60 cursor-not-allowed', className), "data-size": size, ...props, children: ({ isSelected, isIndeterminate: isIndet }) => (_jsxs(_Fragment, { children: [_jsx("span", { className: cn('eidotter-checkbox__box', isSelected && 'eidotter-checkbox__box--checked', isIndet && 'eidotter-checkbox__box--indeterminate'), children: isIndet ? '[-]' : isSelected ? '[X]' : '[ ]' }), label && _jsx("span", { className: "eidotter-checkbox__label", children: label })] })) })));
|
|
11
|
+
Checkbox.displayName = 'Checkbox';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Checkbox } from './Checkbox';
|
|
2
|
-
export type { CheckboxProps } from './Checkbox';
|
|
1
|
+
export { Checkbox } from './Checkbox.js';
|
|
2
|
+
export type { CheckboxProps } from './Checkbox.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox } from './Checkbox.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Checkbox } from './components';
|
|
2
|
-
export type { CheckboxProps } from './components';
|
|
1
|
+
export { Checkbox } from './components/index.js';
|
|
2
|
+
export type { CheckboxProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox } from './components/index.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
const labelToneClasses = {
|
|
5
|
+
default: 'text-dos-text-primary',
|
|
6
|
+
muted: 'text-dos-text-muted line-through',
|
|
7
|
+
error: 'text-dos-error',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* DOS-styled checklist row — a `[x]`/`[ ]` toggle plus label, optional note,
|
|
11
|
+
* and leading/trailing slots. Ported from Steuerdash (DMNC-856).
|
|
12
|
+
*
|
|
13
|
+
* The toggle is a real `<button>` (keyboard + screen-reader operable); the
|
|
14
|
+
* `[x]`/`[ ]` glyph is the DOS checkbox aesthetic. Tones and the note route
|
|
15
|
+
* through `text-dos-*` semantic roles (not raw `cga-*`) so the row re-themes.
|
|
16
|
+
*/
|
|
17
|
+
export const ChecklistRow = ({ checked, onToggle, disabled, pending, ariaLabel, labelTone = 'default', label, children, note, leading, trailing, className, }) => (_jsxs("div", { className: cn('eidotter-checklist-row', 'flex items-start gap-3 py-2 border-b border-dos-border-disabled', pending && 'opacity-50', className), children: [_jsx("button", { type: "button", role: "checkbox", "aria-checked": checked, onClick: onToggle, disabled: disabled, "aria-label": ariaLabel ?? (checked ? 'Mark as incomplete' : 'Mark as complete'), className: cn('shrink-0 pt-0.5 font-dos text-dos-text-sm', 'text-dos-text-primary hover:text-dos-text-accent', 'cursor-pointer disabled:cursor-not-allowed'), children: checked ? '[x]' : '[ ]' }), _jsxs("div", { className: "flex-1 min-w-0", children: [leading && _jsx("div", { className: "mb-1", children: leading }), label !== undefined && (_jsx("div", { className: cn('font-dos text-dos-text-sm', labelToneClasses[labelTone]), children: label })), children, note && _jsx("p", { className: "font-dos text-dos-text-xs text-dos-text-muted mt-0.5", children: note })] }), trailing && _jsx("div", { className: "flex items-center gap-2 shrink-0", children: trailing })] }));
|
|
18
|
+
ChecklistRow.displayName = 'ChecklistRow';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { ChecklistRow } from './ChecklistRow';
|
|
2
|
-
export type { ChecklistRowProps } from './ChecklistRow';
|
|
1
|
+
export { ChecklistRow } from './ChecklistRow.js';
|
|
2
|
+
export type { ChecklistRowProps } from './ChecklistRow.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChecklistRow } from './ChecklistRow.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { ChecklistRow } from './components';
|
|
2
|
-
export type { ChecklistRowProps } from './components';
|
|
1
|
+
export { ChecklistRow } from './components/index.js';
|
|
2
|
+
export type { ChecklistRowProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChecklistRow } from './components/index.js';
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
4
|
+
import { ModalOverlay as AriaModalOverlay, Modal as AriaModal, Dialog as AriaDialog, } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
const defaultFooterHint = (_jsx(_Fragment, { children: "\u2191/\u2193 NAVIGATE \u00B7 \u21B5 OPEN \u00B7 ESC CLOSE" }));
|
|
7
|
+
/** Split hotkey string like "mod+shift+p" into a predicate. */
|
|
8
|
+
function parseHotkey(hotkey) {
|
|
9
|
+
const parts = hotkey.toLowerCase().split('+').map(p => p.trim());
|
|
10
|
+
const key = parts[parts.length - 1];
|
|
11
|
+
const mod = parts.includes('mod');
|
|
12
|
+
const shift = parts.includes('shift');
|
|
13
|
+
const alt = parts.includes('alt');
|
|
14
|
+
return (e) => {
|
|
15
|
+
if (e.key.toLowerCase() !== key)
|
|
16
|
+
return false;
|
|
17
|
+
const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
18
|
+
const modMatches = mod ? (isMac ? e.metaKey : e.ctrlKey) : !(e.metaKey || e.ctrlKey);
|
|
19
|
+
if (!modMatches)
|
|
20
|
+
return false;
|
|
21
|
+
if (shift !== e.shiftKey)
|
|
22
|
+
return false;
|
|
23
|
+
if (alt !== e.altKey)
|
|
24
|
+
return false;
|
|
25
|
+
return true;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Rank items: starts-with on label/keyword ranks first, then substring. */
|
|
29
|
+
function scoreItem(item, query) {
|
|
30
|
+
if (!query)
|
|
31
|
+
return 0;
|
|
32
|
+
const q = query.toLowerCase();
|
|
33
|
+
const label = item.label.toLowerCase();
|
|
34
|
+
const kw = (item.keywords || []).map(k => k.toLowerCase());
|
|
35
|
+
if (label.startsWith(q))
|
|
36
|
+
return 100;
|
|
37
|
+
if (kw.some(k => k.startsWith(q)))
|
|
38
|
+
return 80;
|
|
39
|
+
if (label.includes(q))
|
|
40
|
+
return 50;
|
|
41
|
+
if (kw.some(k => k.includes(q)))
|
|
42
|
+
return 30;
|
|
43
|
+
if ((item.type || '').toLowerCase().includes(q))
|
|
44
|
+
return 10;
|
|
45
|
+
return -1;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* CmdPalette — ⌘K / Ctrl+K launcher overlay.
|
|
49
|
+
*
|
|
50
|
+
* Controlled component. Parent owns `open` and item list; CmdPalette handles
|
|
51
|
+
* search, keyboard navigation, focus management, and hotkey binding.
|
|
52
|
+
*
|
|
53
|
+
* Built on React Aria `ModalOverlay` + `Modal` + `Dialog` — same primitives
|
|
54
|
+
* as `<Modal>` — so focus trap, Esc-to-close, and backdrop dismissal are
|
|
55
|
+
* standard.
|
|
56
|
+
*/
|
|
57
|
+
export const CmdPalette = forwardRef(({ open, onOpenChange, items, placeholder = 'SEARCH · TYPE · ▸', hotkey = 'mod+k', emptyMessage = 'NO MATCHES', footerHint = defaultFooterHint, renderItem, maxResults = 20, className, 'aria-label': ariaLabel = 'Command palette', }, ref) => {
|
|
58
|
+
const baseId = useId();
|
|
59
|
+
const listboxId = `${baseId}-listbox`;
|
|
60
|
+
const [query, setQuery] = useState('');
|
|
61
|
+
const [selected, setSelected] = useState(0);
|
|
62
|
+
const inputRef = useRef(null);
|
|
63
|
+
const listRef = useRef(null);
|
|
64
|
+
// While a keyboard-driven scrollIntoView is flushing, ignore the mouseenter
|
|
65
|
+
// that fires on the item now under the cursor — otherwise arrow keys and
|
|
66
|
+
// a still cursor oscillate the selection.
|
|
67
|
+
const suppressHoverRef = useRef(false);
|
|
68
|
+
// Ranked, filtered results
|
|
69
|
+
const results = useMemo(() => {
|
|
70
|
+
if (!query.trim())
|
|
71
|
+
return items.slice(0, maxResults);
|
|
72
|
+
const scored = items
|
|
73
|
+
.map(i => ({ item: i, score: scoreItem(i, query.trim()) }))
|
|
74
|
+
.filter(s => s.score >= 0)
|
|
75
|
+
.sort((a, b) => b.score - a.score)
|
|
76
|
+
.slice(0, maxResults)
|
|
77
|
+
.map(s => s.item);
|
|
78
|
+
return scored;
|
|
79
|
+
}, [items, query, maxResults]);
|
|
80
|
+
// Reset state when opened
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (open) {
|
|
83
|
+
setQuery('');
|
|
84
|
+
setSelected(0);
|
|
85
|
+
}
|
|
86
|
+
}, [open]);
|
|
87
|
+
// Reset selection when the query changes
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setSelected(0);
|
|
90
|
+
}, [query]);
|
|
91
|
+
// Clamp the selected index when the results list shrinks (e.g. parent mutates
|
|
92
|
+
// `items` while the palette is open). Prevents aria-activedescendant pointing
|
|
93
|
+
// at a non-existent id and Enter becoming a no-op until the user touches an
|
|
94
|
+
// arrow key.
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
setSelected(s => Math.min(s, Math.max(0, results.length - 1)));
|
|
97
|
+
}, [results.length]);
|
|
98
|
+
// Focus input when open (React Aria handles focus trap; we steer to input)
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (open) {
|
|
101
|
+
const id = window.setTimeout(() => inputRef.current?.focus(), 10);
|
|
102
|
+
return () => window.clearTimeout(id);
|
|
103
|
+
}
|
|
104
|
+
}, [open]);
|
|
105
|
+
// Keep latest open/onOpenChange accessible without rebinding the global listener.
|
|
106
|
+
// Parents commonly pass an inline onOpenChange, which would otherwise re-attach
|
|
107
|
+
// the keydown listener on every render.
|
|
108
|
+
const openRef = useRef(open);
|
|
109
|
+
const onOpenChangeRef = useRef(onOpenChange);
|
|
110
|
+
useEffect(() => { openRef.current = open; }, [open]);
|
|
111
|
+
useEffect(() => { onOpenChangeRef.current = onOpenChange; }, [onOpenChange]);
|
|
112
|
+
// Global hotkey — rebinds only when `hotkey` itself changes.
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (hotkey === false)
|
|
115
|
+
return;
|
|
116
|
+
const predicate = parseHotkey(hotkey);
|
|
117
|
+
const handler = (e) => {
|
|
118
|
+
if (predicate(e)) {
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
onOpenChangeRef.current(!openRef.current);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
window.addEventListener('keydown', handler);
|
|
124
|
+
return () => window.removeEventListener('keydown', handler);
|
|
125
|
+
}, [hotkey]);
|
|
126
|
+
// Keep the selected row scrolled into view
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!open || results.length === 0)
|
|
129
|
+
return;
|
|
130
|
+
const el = listRef.current?.querySelector(`[data-index="${selected}"]`);
|
|
131
|
+
// jsdom doesn't implement scrollIntoView — guard so tests don't throw.
|
|
132
|
+
if (el && typeof el.scrollIntoView === 'function') {
|
|
133
|
+
suppressHoverRef.current = true;
|
|
134
|
+
el.scrollIntoView({ block: 'nearest' });
|
|
135
|
+
const id = window.setTimeout(() => { suppressHoverRef.current = false; }, 0);
|
|
136
|
+
return () => window.clearTimeout(id);
|
|
137
|
+
}
|
|
138
|
+
}, [selected, results, open]);
|
|
139
|
+
const handleSelect = useCallback((item) => {
|
|
140
|
+
item.onSelect?.(item);
|
|
141
|
+
onOpenChange(false);
|
|
142
|
+
}, [onOpenChange]);
|
|
143
|
+
const handleKeyDown = (e) => {
|
|
144
|
+
if (e.key === 'ArrowDown') {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
setSelected(i => Math.min(i + 1, Math.max(0, results.length - 1)));
|
|
147
|
+
}
|
|
148
|
+
else if (e.key === 'ArrowUp') {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
setSelected(i => Math.max(0, i - 1));
|
|
151
|
+
}
|
|
152
|
+
else if (e.key === 'Enter') {
|
|
153
|
+
const item = results[selected];
|
|
154
|
+
if (item) {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
handleSelect(item);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
return (_jsx(AriaModalOverlay, { isOpen: open, onOpenChange: onOpenChange, isDismissable: true, className: ({ isEntering, isExiting }) => cn('eidotter-cmdpal-overlay', isEntering && 'eidotter-cmdpal-overlay--entering', isExiting && 'eidotter-cmdpal-overlay--exiting'), children: _jsx(AriaModal, { className: ({ isEntering, isExiting }) => cn('eidotter-cmdpal', isEntering && 'eidotter-cmdpal--entering', isExiting && 'eidotter-cmdpal--exiting'), children: _jsxs(AriaDialog, { "aria-label": ariaLabel, className: cn('eidotter-cmdpal__container outline-none', className), ref: ref, children: [_jsxs("div", { className: "eidotter-cmdpal__head", "aria-hidden": "true", children: [_jsx("span", { children: "\u25B8 JUMP TO" }), _jsx("span", { className: "eidotter-cmdpal__blink", children: "_" })] }), _jsx("input", { ref: inputRef, type: "text", role: "combobox", "aria-controls": listboxId, "aria-expanded": true, "aria-autocomplete": "list", "aria-activedescendant": results[selected] ? `${baseId}-item-${results[selected].id}` : undefined, className: "eidotter-cmdpal__input", value: query, placeholder: placeholder, onChange: e => setQuery(e.target.value), onKeyDown: handleKeyDown }), _jsxs("ul", { ref: listRef, id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "eidotter-cmdpal__results", children: [results.length === 0 && (_jsx("li", { className: "eidotter-cmdpal__empty", role: "presentation", children: emptyMessage })), results.map((item, i) => {
|
|
161
|
+
const isSelected = i === selected;
|
|
162
|
+
return (_jsx("li", { id: `${baseId}-item-${item.id}`, role: "option", "aria-selected": isSelected, "data-index": i, className: cn('eidotter-cmdpal__item', isSelected && 'eidotter-cmdpal__item--selected'), onMouseMove: () => {
|
|
163
|
+
if (suppressHoverRef.current)
|
|
164
|
+
return;
|
|
165
|
+
setSelected(i);
|
|
166
|
+
}, onClick: () => handleSelect(item), children: renderItem ? renderItem(item, isSelected) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "eidotter-cmdpal__item-label", children: [_jsx("span", { className: "eidotter-cmdpal__item-caret", "aria-hidden": "true", children: isSelected ? '▸' : ' ' }), item.label] }), item.hint !== undefined && (_jsx("span", { className: "eidotter-cmdpal__item-hint", children: item.hint }))] })) }, item.id));
|
|
167
|
+
})] }), footerHint && (_jsx("div", { className: "eidotter-cmdpal__footer", "aria-hidden": "true", children: footerHint }))] }) }) }));
|
|
168
|
+
});
|
|
169
|
+
CmdPalette.displayName = 'CmdPalette';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CmdPalette } from './CmdPalette';
|
|
2
|
-
export type { CmdPaletteProps, CmdPaletteItem } from './CmdPalette';
|
|
1
|
+
export { CmdPalette } from './CmdPalette.js';
|
|
2
|
+
export type { CmdPaletteProps, CmdPaletteItem } from './CmdPalette.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CmdPalette } from './CmdPalette.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CmdPalette } from './components';
|
|
2
|
-
export type { CmdPaletteProps, CmdPaletteItem } from './components';
|
|
1
|
+
export { CmdPalette } from './components/index.js';
|
|
2
|
+
export type { CmdPaletteProps, CmdPaletteItem } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CmdPalette } from './components/index.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* DOS-styled CommandPrompt component with authentic terminal aesthetics
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Configurable prompt string (e.g., "C:\>", "$")
|
|
9
|
+
* - Enter key triggers onCommand callback
|
|
10
|
+
* - Blinking cursor for DOS feel
|
|
11
|
+
* - Auto-focus support
|
|
12
|
+
* - WCAG 2.1 AA compliant
|
|
13
|
+
*/
|
|
14
|
+
export const CommandPrompt = ({ prompt = 'C:\\>', onCommand, autoFocus = false, className = '', placeholder, disabled = false, }) => {
|
|
15
|
+
const [value, setValue] = useState('');
|
|
16
|
+
const inputRef = useRef(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (autoFocus && inputRef.current) {
|
|
19
|
+
inputRef.current.focus();
|
|
20
|
+
}
|
|
21
|
+
}, [autoFocus]);
|
|
22
|
+
const handleKeyDown = (e) => {
|
|
23
|
+
if (e.key === 'Enter' && value.trim() && !disabled) {
|
|
24
|
+
onCommand(value.trim());
|
|
25
|
+
setValue('');
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const handleContainerClick = () => {
|
|
29
|
+
if (!disabled && inputRef.current) {
|
|
30
|
+
inputRef.current.focus();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return (_jsxs("div", { className: `command-prompt ${disabled ? 'command-prompt--disabled' : ''} ${className}`.trim(), onClick: handleContainerClick, children: [_jsx("span", { className: "command-prompt__prompt", "aria-hidden": "true", children: prompt }), _jsxs("div", { className: "command-prompt__input-wrapper", children: [_jsx("input", { ref: inputRef, className: "command-prompt__input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, autoFocus: autoFocus, spellCheck: false, autoComplete: "off", autoCapitalize: "off", autoCorrect: "off", placeholder: placeholder, disabled: disabled, "aria-label": "Command input", size: value.length || 1 }), _jsx("span", { className: "command-prompt__cursor", "aria-hidden": "true", children: "\u2588" })] })] }));
|
|
34
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CommandPrompt } from './CommandPrompt';
|
|
2
|
-
export type { CommandPromptProps } from './CommandPrompt';
|
|
1
|
+
export { CommandPrompt } from './CommandPrompt.js';
|
|
2
|
+
export type { CommandPromptProps } from './CommandPrompt.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CommandPrompt } from './CommandPrompt.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './components';
|
|
1
|
+
export * from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/index.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useRef, useState } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
/**
|
|
6
|
+
* DOS-styled copy-to-clipboard button — shows `[cp]`, flips to `[OK]` for ~1.5s
|
|
7
|
+
* after a successful copy. Uses the async Clipboard API with a `execCommand`
|
|
8
|
+
* fallback. Ported from Steuerdash (DMNC-858); English default labels (was
|
|
9
|
+
* German) and `text-dos-link` semantic roles.
|
|
10
|
+
*/
|
|
11
|
+
export const CopyButton = ({ value, label = '[cp]', copiedLabel = '[OK]', title = 'Copy to clipboard', copiedTitle = 'Copied!', className, }) => {
|
|
12
|
+
const [copied, setCopied] = useState(false);
|
|
13
|
+
const timerRef = useRef(null);
|
|
14
|
+
const markCopied = useCallback(() => {
|
|
15
|
+
setCopied(true);
|
|
16
|
+
if (timerRef.current)
|
|
17
|
+
clearTimeout(timerRef.current);
|
|
18
|
+
timerRef.current = setTimeout(() => setCopied(false), 1500);
|
|
19
|
+
}, []);
|
|
20
|
+
const fallbackCopy = useCallback(() => {
|
|
21
|
+
const ta = document.createElement('textarea');
|
|
22
|
+
ta.value = value;
|
|
23
|
+
ta.style.position = 'fixed';
|
|
24
|
+
ta.style.opacity = '0';
|
|
25
|
+
document.body.appendChild(ta);
|
|
26
|
+
ta.select();
|
|
27
|
+
try {
|
|
28
|
+
const ok = document.execCommand('copy');
|
|
29
|
+
ta.remove();
|
|
30
|
+
return ok;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
ta.remove();
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}, [value]);
|
|
37
|
+
const copy = useCallback(() => {
|
|
38
|
+
if (navigator.clipboard?.writeText) {
|
|
39
|
+
navigator.clipboard.writeText(value).then(markCopied).catch(() => {
|
|
40
|
+
if (fallbackCopy())
|
|
41
|
+
markCopied();
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (fallbackCopy()) {
|
|
45
|
+
markCopied();
|
|
46
|
+
}
|
|
47
|
+
}, [value, markCopied, fallbackCopy]);
|
|
48
|
+
return (_jsx("button", { type: "button", onClick: copy, title: copied ? copiedTitle : title, "aria-label": copied ? copiedTitle : title, className: cn('eidotter-copy-button', 'font-dos text-dos-text-xs px-1', 'text-dos-link hover:text-dos-link-hover cursor-pointer', className), children: copied ? copiedLabel : label }));
|
|
49
|
+
};
|
|
50
|
+
CopyButton.displayName = 'CopyButton';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CopyButton } from './CopyButton';
|
|
2
|
-
export type { CopyButtonProps } from './CopyButton';
|
|
1
|
+
export { CopyButton } from './CopyButton.js';
|
|
2
|
+
export type { CopyButtonProps } from './CopyButton.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CopyButton } from './CopyButton.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CopyButton } from './components';
|
|
2
|
-
export type { CopyButtonProps } from './components';
|
|
1
|
+
export { CopyButton } from './components/index.js';
|
|
2
|
+
export type { CopyButtonProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CopyButton } from './components/index.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useId } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
/**
|
|
6
|
+
* DosFigure — demoscene-style placeholder for media.
|
|
7
|
+
*
|
|
8
|
+
* Sierra / LucasArts / demoscene title cards painted the screen with a
|
|
9
|
+
* limited palette, dithering, and annotated frames. DosFigure recreates
|
|
10
|
+
* that aesthetic: amber chrome, scanline sweep, optional pins, and a
|
|
11
|
+
* resolution tag. Use as a lead-in for blog articles or as a placeholder
|
|
12
|
+
* where a photograph would otherwise go.
|
|
13
|
+
*
|
|
14
|
+
* Not intended as a replacement for semantic imagery — pass `aria-label`
|
|
15
|
+
* (or a `<figcaption>` via `caption`) so the figure is meaningful to AT.
|
|
16
|
+
*/
|
|
17
|
+
export const DosFigure = forwardRef(({ title, resolution, subject, caption, pins = [], animated = true, 'aria-label': ariaLabel, className, }, ref) => {
|
|
18
|
+
const captionId = useId();
|
|
19
|
+
const describedById = caption ? captionId : undefined;
|
|
20
|
+
return (_jsxs("figure", { ref: ref, className: cn('eidotter-dos-figure', animated && 'eidotter-dos-figure--animated', className), role: "img", "aria-label": ariaLabel, "aria-describedby": describedById, children: [title && (_jsx("div", { className: "eidotter-dos-figure__title", "aria-hidden": "true", children: _jsx("span", { children: title }) })), _jsxs("div", { className: "eidotter-dos-figure__frame", children: [_jsx("div", { className: "eidotter-dos-figure__subject", children: subject }), pins.length > 0 && (_jsx("ul", { className: "eidotter-dos-figure__pins", role: "list", children: pins.map((pin, idx) => {
|
|
21
|
+
const x = Number.isFinite(pin.x) ? Math.max(0, Math.min(100, pin.x)) : 0;
|
|
22
|
+
const y = Number.isFinite(pin.y) ? Math.max(0, Math.min(100, pin.y)) : 0;
|
|
23
|
+
return (_jsxs("li", { className: "eidotter-dos-figure__pin", style: { left: `${x}%`, top: `${y}%` }, children: [_jsx("span", { className: "eidotter-dos-figure__pin-dot", "aria-hidden": "true" }), _jsx("span", { className: "eidotter-dos-figure__pin-label", children: pin.label })] }, `${x}-${y}-${idx}`));
|
|
24
|
+
}) })), _jsx("span", { className: "eidotter-dos-figure__scanline", "aria-hidden": "true" }), resolution && (_jsx("span", { className: "eidotter-dos-figure__resolution", "aria-hidden": "true", children: resolution }))] }), caption && (_jsx("figcaption", { id: captionId, className: "eidotter-dos-figure__caption", children: caption }))] }));
|
|
25
|
+
});
|
|
26
|
+
DosFigure.displayName = 'DosFigure';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { DosFigure } from './DosFigure';
|
|
2
|
-
export type { DosFigureProps, DosFigurePin } from './DosFigure';
|
|
1
|
+
export { DosFigure } from './DosFigure.js';
|
|
2
|
+
export type { DosFigureProps, DosFigurePin } from './DosFigure.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DosFigure } from './DosFigure.js';
|