eidotter 0.36.0 → 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/eidotter.css +1 -1
- 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
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { DosFigure } from './components';
|
|
2
|
-
export type { DosFigureProps, DosFigurePin } from './components';
|
|
1
|
+
export { DosFigure } from './components/index.js';
|
|
2
|
+
export type { DosFigureProps, DosFigurePin } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DosFigure } from './components/index.js';
|
|
@@ -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 toneClasses = {
|
|
4
|
+
default: 'text-dos-text-primary',
|
|
5
|
+
error: 'text-dos-error',
|
|
6
|
+
warning: 'text-dos-warning',
|
|
7
|
+
info: 'text-dos-info',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* DOS-styled empty / zero-state — a centred title, optional description, and an
|
|
11
|
+
* optional action slot. Pure presentational.
|
|
12
|
+
*
|
|
13
|
+
* Ported from Steuerdash (DMNC-859); tones and the description route through
|
|
14
|
+
* `text-dos-*` semantic roles (not raw `cga-*`) so it re-themes and the
|
|
15
|
+
* description stays AA-safe (`text-muted` → lightGray under amber-mono).
|
|
16
|
+
*/
|
|
17
|
+
export const EmptyState = ({ title, description, tone = 'default', action, className, }) => (_jsxs("div", { className: cn('eidotter-empty-state', 'flex flex-col gap-2 py-6 text-center', className), role: "status", children: [_jsx("p", { className: cn('font-dos text-dos-text-sm', toneClasses[tone]), children: title }), description && (_jsx("p", { className: "font-dos text-dos-text-xs text-dos-text-muted", children: description })), action && _jsx("div", { className: "mt-2", children: action })] }));
|
|
18
|
+
EmptyState.displayName = 'EmptyState';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { EmptyState } from './EmptyState';
|
|
2
|
-
export type { EmptyStateProps } from './EmptyState';
|
|
1
|
+
export { EmptyState } from './EmptyState.js';
|
|
2
|
+
export type { EmptyStateProps } from './EmptyState.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EmptyState } from './EmptyState.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { EmptyState } from './components';
|
|
2
|
-
export type { EmptyStateProps } from './components';
|
|
1
|
+
export { EmptyState } from './components/index.js';
|
|
2
|
+
export type { EmptyStateProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EmptyState } from './components/index.js';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback, useRef } from 'react';
|
|
4
|
+
import { Button as AriaButton } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
/**
|
|
7
|
+
* DOS-styled FilterBar component for multi-select or single-select content filtering
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Multi-select (default) or single-select mode
|
|
11
|
+
* - Optional count badges on each filter item
|
|
12
|
+
* - Optional "All" toggle that selects/deselects everything
|
|
13
|
+
* - Full keyboard navigation (Arrow keys, Space, Enter, Home, End)
|
|
14
|
+
* - Controlled and uncontrolled modes
|
|
15
|
+
* - DOS-authentic styling with CGA colors
|
|
16
|
+
* - WCAG 2.1 AA compliant
|
|
17
|
+
* - prefers-reduced-motion support
|
|
18
|
+
* - prefers-contrast: high support
|
|
19
|
+
*/
|
|
20
|
+
const sizeClasses = {
|
|
21
|
+
sm: 'eidotter-filter-bar--sm',
|
|
22
|
+
md: 'eidotter-filter-bar--md',
|
|
23
|
+
lg: 'eidotter-filter-bar--lg',
|
|
24
|
+
small: 'eidotter-filter-bar--sm',
|
|
25
|
+
medium: 'eidotter-filter-bar--md',
|
|
26
|
+
large: 'eidotter-filter-bar--lg',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* DOS-styled FilterBar for multi-select or single-select content filtering.
|
|
30
|
+
* Pure presentational — uses CSS transitions for phosphor effects.
|
|
31
|
+
*/
|
|
32
|
+
export const FilterBar = ({ items, activeIds, defaultActiveIds = [], mode = 'multi', showAll = false, allLabel = 'All', size = 'md', onChange, className, ...props }) => {
|
|
33
|
+
const [internalActiveIds, setInternalActiveIds] = useState(defaultActiveIds);
|
|
34
|
+
const toolbarRef = useRef(null);
|
|
35
|
+
const isControlled = activeIds !== undefined;
|
|
36
|
+
const currentActiveIds = isControlled ? activeIds : internalActiveIds;
|
|
37
|
+
// All non-disabled item IDs
|
|
38
|
+
const enabledItemIds = items.filter(item => !item.disabled).map(item => item.id);
|
|
39
|
+
// Whether "All" is logically active (no specific filters selected)
|
|
40
|
+
const isAllActive = currentActiveIds.length === 0;
|
|
41
|
+
const updateSelection = useCallback((newIds) => {
|
|
42
|
+
if (!isControlled) {
|
|
43
|
+
setInternalActiveIds(newIds);
|
|
44
|
+
}
|
|
45
|
+
onChange?.(newIds);
|
|
46
|
+
}, [isControlled, onChange]);
|
|
47
|
+
const handleItemToggle = useCallback((itemId) => {
|
|
48
|
+
if (mode === 'single') {
|
|
49
|
+
// In single mode, toggle the item or deselect it
|
|
50
|
+
const newIds = currentActiveIds.includes(itemId) ? [] : [itemId];
|
|
51
|
+
updateSelection(newIds);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// In multi mode, toggle the item on/off
|
|
55
|
+
const newIds = currentActiveIds.includes(itemId)
|
|
56
|
+
? currentActiveIds.filter(id => id !== itemId)
|
|
57
|
+
: [...currentActiveIds, itemId];
|
|
58
|
+
updateSelection(newIds);
|
|
59
|
+
}
|
|
60
|
+
}, [mode, currentActiveIds, updateSelection]);
|
|
61
|
+
const handleAllToggle = useCallback(() => {
|
|
62
|
+
// Selecting "All" clears all individual selections
|
|
63
|
+
updateSelection([]);
|
|
64
|
+
}, [updateSelection]);
|
|
65
|
+
// Build the list of all focusable button refs: [All?, ...items]
|
|
66
|
+
const getButtons = useCallback(() => {
|
|
67
|
+
if (!toolbarRef.current)
|
|
68
|
+
return [];
|
|
69
|
+
return Array.from(toolbarRef.current.querySelectorAll('button:not([disabled])'));
|
|
70
|
+
}, []);
|
|
71
|
+
const handleKeyDown = useCallback((event) => {
|
|
72
|
+
const buttons = getButtons();
|
|
73
|
+
const currentIndex = buttons.indexOf(event.target);
|
|
74
|
+
if (currentIndex === -1)
|
|
75
|
+
return;
|
|
76
|
+
let newIndex = null;
|
|
77
|
+
switch (event.key) {
|
|
78
|
+
case 'ArrowLeft':
|
|
79
|
+
case 'ArrowUp':
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
newIndex = currentIndex > 0 ? currentIndex - 1 : buttons.length - 1;
|
|
82
|
+
break;
|
|
83
|
+
case 'ArrowRight':
|
|
84
|
+
case 'ArrowDown':
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
newIndex = currentIndex < buttons.length - 1 ? currentIndex + 1 : 0;
|
|
87
|
+
break;
|
|
88
|
+
case 'Home':
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
newIndex = 0;
|
|
91
|
+
break;
|
|
92
|
+
case 'End':
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
newIndex = buttons.length - 1;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
if (newIndex !== null) {
|
|
98
|
+
buttons[newIndex].focus();
|
|
99
|
+
}
|
|
100
|
+
}, [getButtons]);
|
|
101
|
+
// Determine the currently focused index for roving tabindex
|
|
102
|
+
// The first active item gets tabIndex 0, or the All button, or the first enabled item
|
|
103
|
+
const getFocusableId = () => {
|
|
104
|
+
if (showAll && isAllActive)
|
|
105
|
+
return '__all__';
|
|
106
|
+
if (currentActiveIds.length > 0)
|
|
107
|
+
return currentActiveIds[0];
|
|
108
|
+
if (showAll)
|
|
109
|
+
return '__all__';
|
|
110
|
+
return enabledItemIds[0] || null;
|
|
111
|
+
};
|
|
112
|
+
const focusableId = getFocusableId();
|
|
113
|
+
return (_jsxs("div", { ref: toolbarRef, className: cn('inline-flex flex-wrap items-center gap-1 p-1 font-dos max-w-full', 'bg-dos-bg-secondary border border-dos-border-default rounded-dos-sm', 'eidotter-filter-bar', sizeClasses[size] || sizeClasses.md, className), role: "toolbar", onKeyDown: handleKeyDown, ...props, children: [showAll && (_jsx(AriaButton, { className: cn('eidotter-filter-bar__item', 'eidotter-filter-bar__item--all', isAllActive && 'eidotter-filter-bar__item--active'), "aria-pressed": isAllActive, excludeFromTabOrder: focusableId !== '__all__', onPress: handleAllToggle, children: _jsx("span", { className: "eidotter-filter-bar__label", children: allLabel }) })), items.map((item) => {
|
|
114
|
+
const isActive = currentActiveIds.includes(item.id);
|
|
115
|
+
const style = isActive && item.color
|
|
116
|
+
? { '--filter-bar-item-color': `var(${item.color})` }
|
|
117
|
+
: undefined;
|
|
118
|
+
return (_jsxs(AriaButton, { className: cn('eidotter-filter-bar__item', isActive && 'eidotter-filter-bar__item--active', item.disabled && 'eidotter-filter-bar__item--disabled'), "aria-pressed": isActive, excludeFromTabOrder: focusableId !== item.id, isDisabled: item.disabled, onPress: () => handleItemToggle(item.id), style: style, children: [_jsx("span", { className: "eidotter-filter-bar__label", children: item.label }), item.count !== undefined && (_jsx("span", { className: "eidotter-filter-bar__count", "aria-label": `${item.count} items`, children: item.count }))] }, item.id));
|
|
119
|
+
})] }));
|
|
120
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { FilterBar } from './FilterBar';
|
|
2
|
-
export type { FilterBarProps, FilterBarItem } from './FilterBar';
|
|
1
|
+
export { FilterBar } from './FilterBar.js';
|
|
2
|
+
export type { FilterBarProps, FilterBarItem } from './FilterBar.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FilterBar } from './FilterBar.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { FilterBar } from './components';
|
|
2
|
-
export type { FilterBarProps, FilterBarItem } from './components';
|
|
1
|
+
export { FilterBar } from './components/index.js';
|
|
2
|
+
export type { FilterBarProps, FilterBarItem } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FilterBar } from './components/index.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
/** Default legal links for German compliance (DDG § 5 / GDPR) */
|
|
5
|
+
export const defaultLegalLinks = [
|
|
6
|
+
{ label: 'Impressum', href: '/impressum' },
|
|
7
|
+
{ label: 'Datenschutz', href: '/datenschutz' },
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* DOS-themed footer with copyright and configurable legal/nav links.
|
|
11
|
+
* Pure presentational — uses middle-dot separators for terminal aesthetic.
|
|
12
|
+
*/
|
|
13
|
+
export const Footer = ({ copyright, links, linkComponent, children, className, ...props }) => {
|
|
14
|
+
const resolvedLinks = links ?? defaultLegalLinks;
|
|
15
|
+
const LinkTag = linkComponent ?? 'a';
|
|
16
|
+
const linkClassName = 'eidotter-footer__link text-dos-text-brand no-underline';
|
|
17
|
+
return (_jsxs("footer", { className: cn('font-dos text-sm py-4 px-2 text-center', 'eidotter-footer', className), ...props, children: [_jsx("div", { className: "h-px bg-dos-border-default mb-4", role: "separator" }), children && _jsx("div", { className: "mb-3", children: children }), resolvedLinks.length > 0 && (_jsx("nav", { className: "flex justify-center items-center flex-wrap gap-2 mb-2", "aria-label": "Footer links", children: resolvedLinks.map((link, index) => (_jsxs(React.Fragment, { children: [index > 0 && _jsx("span", { className: "text-dos-text-muted select-none eidotter-footer__dot", "aria-hidden": "true", children: "\u00B7" }), link.external ? (_jsx("a", { className: linkClassName, href: link.href, target: "_blank", rel: "noopener noreferrer", children: link.label })) : (_jsx(LinkTag, { className: linkClassName, href: link.href, children: link.label }))] }, link.href))) })), copyright && (_jsxs("p", { className: "text-dos-text-muted m-0", children: ["\u00A9 ", copyright] }))] }));
|
|
18
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Footer, defaultLegalLinks } from './Footer';
|
|
2
|
-
export type { FooterProps, FooterLink } from './Footer';
|
|
1
|
+
export { Footer, defaultLegalLinks } from './Footer.js';
|
|
2
|
+
export type { FooterProps, FooterLink } from './Footer.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Footer, defaultLegalLinks } from './Footer.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Footer, defaultLegalLinks } from './components';
|
|
2
|
-
export type { FooterProps, FooterLink } from './components';
|
|
1
|
+
export { Footer, defaultLegalLinks } from './components/index.js';
|
|
2
|
+
export type { FooterProps, FooterLink } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Footer, defaultLegalLinks } from './components/index.js';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { NavItem, NavProps } from '../../Nav';
|
|
3
|
-
import './Header.css';
|
|
2
|
+
import type { NavItem, NavProps } from '../../Nav/index.js';
|
|
4
3
|
export interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
|
|
5
4
|
/** Site brand name displayed in the header */
|
|
6
5
|
brandName?: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { DesktopNav, MobileNav } from '../../Nav/index.js';
|
|
5
|
+
const variantClasses = {
|
|
6
|
+
retro: 'eidotter-header--retro',
|
|
7
|
+
modern: 'eidotter-header--modern',
|
|
8
|
+
};
|
|
9
|
+
export const Header = forwardRef(({ brandName, brandHref = '/', items, activeHref, variant = 'retro', sticky = true, linkComponent, children, className, ...rest }, ref) => {
|
|
10
|
+
const LinkTag = linkComponent ?? 'a';
|
|
11
|
+
return (_jsxs("header", { ref: ref, className: cn('flex items-center justify-between px-4 py-3 font-dos', 'eidotter-header', variantClasses[variant], sticky && 'sticky top-0 z-50 bg-dos-bg-primary', className), ...rest, children: [_jsx(LinkTag, { href: brandHref, className: cn('no-underline text-base font-bold tracking-wide', 'eidotter-header__branding'), children: children || brandName }), _jsx(DesktopNav, { items: items, activeHref: activeHref, variant: variant, linkComponent: linkComponent }), _jsx(MobileNav, { items: items, activeHref: activeHref, variant: variant, linkComponent: linkComponent })] }));
|
|
12
|
+
});
|
|
13
|
+
Header.displayName = 'Header';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Header } from './Header';
|
|
2
|
-
export type { HeaderProps } from './Header';
|
|
1
|
+
export { Header } from './Header.js';
|
|
2
|
+
export type { HeaderProps } from './Header.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Header } from './Header.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Header } from './components';
|
|
2
|
-
export type { HeaderProps } from './components';
|
|
1
|
+
export { Header } from './components/index.js';
|
|
2
|
+
export type { HeaderProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Header } from './components/index.js';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { InfoBox } from 'pixelarticons/react/InfoBox';
|
|
4
|
+
import { WarningDiamond } from 'pixelarticons/react/WarningDiamond';
|
|
5
|
+
import { SquareAlert } from 'pixelarticons/react/SquareAlert';
|
|
6
|
+
import { Check } from 'pixelarticons/react/Check';
|
|
7
|
+
import { ChevronUp } from 'pixelarticons/react/ChevronUp';
|
|
8
|
+
import { ChevronDown } from 'pixelarticons/react/ChevronDown';
|
|
9
|
+
import { WindowFrame } from 'pixelarticons/react/WindowFrame';
|
|
10
|
+
import { Minus } from 'pixelarticons/react/Minus';
|
|
11
|
+
import { Expand } from 'pixelarticons/react/Expand';
|
|
12
|
+
import { Plus } from 'pixelarticons/react/Plus';
|
|
13
|
+
import { cn } from '../../../utils/cn.js';
|
|
14
|
+
/**
|
|
15
|
+
* Custom pixel-art X mark — pixelarticons v2 has no standalone close/X glyph.
|
|
16
|
+
* Matches pixelarticons' style: 24×24 viewBox, fill-based single path,
|
|
17
|
+
* currentColor inheritance, 2×2 unit "pixels" on the grid.
|
|
18
|
+
*/
|
|
19
|
+
const PixelX = (props) => (_jsx("svg", { viewBox: "0 0 24 24", width: "24", height: "24", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", ...props, children: _jsx("path", { d: "M5 5h2v2H5zM7 7h2v2H7zM9 9h2v2H9zM11 11h2v2h-2zM13 13h2v2h-2zM15 15h2v2h-2zM17 17h2v2h-2zM17 5h2v2h-2zM15 7h2v2h-2zM13 9h2v2h-2zM9 13h2v2H9zM7 15h2v2H7zM5 17h2v2H5z" }) }));
|
|
20
|
+
// 12 public icon names mapping to 11 unique pixelarticons components.
|
|
21
|
+
// Done and Check both map to the Check component intentionally — consumers
|
|
22
|
+
// can use either semantic name for a checkmark glyph.
|
|
23
|
+
//
|
|
24
|
+
// Non-obvious mappings:
|
|
25
|
+
// - 'Close' → custom PixelX component: pixelarticons v2 has no standalone
|
|
26
|
+
// X/close glyph, so we draw a pixel-art X mark matching their style
|
|
27
|
+
// (24×24 viewBox, fill-based single path, 2×2 unit pixels).
|
|
28
|
+
// - 'Cancel' → pixelarticons Minus: this name carries Terminal-window semantics
|
|
29
|
+
// (cancel/minimize control), rendered as a minus glyph matching DOS window
|
|
30
|
+
// chrome. A future release may rename this to 'Minimize' for clarity.
|
|
31
|
+
// - 'App' → pixelarticons WindowFrame: used for the Terminal window icon.
|
|
32
|
+
const ICON_MAP = {
|
|
33
|
+
'Info': InfoBox,
|
|
34
|
+
'Warning': WarningDiamond,
|
|
35
|
+
'Error': SquareAlert,
|
|
36
|
+
'Done': Check,
|
|
37
|
+
'Check': Check,
|
|
38
|
+
'Close': PixelX, // custom pixel-art X mark (pixelarticons has no X glyph)
|
|
39
|
+
'Chevron Up': ChevronUp,
|
|
40
|
+
'Chevron Down': ChevronDown,
|
|
41
|
+
'App': WindowFrame,
|
|
42
|
+
'Cancel': Minus, // window minimize control, not abort
|
|
43
|
+
'Fullscreen': Expand,
|
|
44
|
+
'Add': Plus,
|
|
45
|
+
};
|
|
46
|
+
const SIZE_MAP = { L: 56, S: 24 };
|
|
47
|
+
/**
|
|
48
|
+
* Icon component backed by pixelarticons (MIT licensed).
|
|
49
|
+
* Renders inline SVG with proper viewBox scaling at any size.
|
|
50
|
+
* The DOS pixel aesthetic matches eidotter's design language.
|
|
51
|
+
*/
|
|
52
|
+
export const Icon = ({ name, size = 'L', className = '', onClick, color, role, 'aria-label': ariaLabel, }) => {
|
|
53
|
+
// Runtime defense against JS consumers or dynamically-cast names.
|
|
54
|
+
// TypeScript users are already constrained to IconName by IconProps.
|
|
55
|
+
const IconComponent = ICON_MAP[name];
|
|
56
|
+
if (!IconComponent)
|
|
57
|
+
return null;
|
|
58
|
+
const pixelSize = SIZE_MAP[size];
|
|
59
|
+
// Default to role="img" so the aria-label is allowed (ARIA 1.2 prohibits
|
|
60
|
+
// aria-label on the implicit `generic` role of <span>). When the consumer
|
|
61
|
+
// marks the icon as an interactive control via role="button", that takes
|
|
62
|
+
// precedence and the consumer is responsible for handling activation.
|
|
63
|
+
const resolvedRole = role ?? 'img';
|
|
64
|
+
const isButton = role === 'button';
|
|
65
|
+
// When the icon is itself the interactive control (role="button"), make it
|
|
66
|
+
// keyboard-operable: focusable + Enter/Space activation, matching native
|
|
67
|
+
// button behavior. Without this the shipped :focus-visible style can never
|
|
68
|
+
// fire because the span isn't in the tab order.
|
|
69
|
+
const handleKeyDown = isButton
|
|
70
|
+
? (event) => {
|
|
71
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
onClick?.();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
return (_jsx("span", { className: cn('icon', isButton && 'icon--button', className), onClick: onClick, onKeyDown: handleKeyDown, role: resolvedRole, tabIndex: isButton ? 0 : undefined, "aria-label": ariaLabel || `${name} icon`, style: color ? { color } : undefined, children: _jsx(IconComponent, { width: pixelSize, height: pixelSize, className: "icon__svg" }) }));
|
|
78
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Icon } from './Icon';
|
|
2
|
-
export type { IconProps, IconName, IconSize } from './Icon';
|
|
1
|
+
export { Icon } from './Icon.js';
|
|
2
|
+
export type { IconProps, IconName, IconSize } from './Icon.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Icon } from './Icon.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, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useId, useRef } from 'react';
|
|
4
|
+
import { Button as AriaButton } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
import { isSafeUrl } from '../../../utils/isSafeUrl.js';
|
|
7
|
+
/**
|
|
8
|
+
* Inline disclosure widget that reveals content when trigger text is clicked.
|
|
9
|
+
*
|
|
10
|
+
* Unlike Section/Accordion (block-level, bordered sections), InlineExpand is
|
|
11
|
+
* designed for inline use within paragraphs and prose content.
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - Controlled and uncontrolled modes
|
|
15
|
+
* - Native <button> trigger for full keyboard/screen reader support
|
|
16
|
+
* - Optional citation sources with favicons
|
|
17
|
+
* - DOS-authentic styling with phosphor glow and CGA tokens
|
|
18
|
+
* - WCAG 2.1 AA compliant
|
|
19
|
+
*
|
|
20
|
+
* Content stays in the DOM when collapsed (with visibility: hidden) to enable
|
|
21
|
+
* smooth CSS transition exit animations. This differs from Section which
|
|
22
|
+
* unmounts content on collapse via conditional rendering.
|
|
23
|
+
*/
|
|
24
|
+
export const InlineExpand = ({ children, content, defaultExpanded = false, expanded, onToggle, sources = [], className, ...props }) => {
|
|
25
|
+
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
|
|
26
|
+
const [failedFavicons, setFailedFavicons] = useState(new Set());
|
|
27
|
+
const hasBeenExpanded = useRef(defaultExpanded);
|
|
28
|
+
const contentId = useId();
|
|
29
|
+
const triggerRef = useRef(null);
|
|
30
|
+
const isControlled = expanded !== undefined;
|
|
31
|
+
const isExpanded = isControlled ? expanded : internalExpanded;
|
|
32
|
+
if (isExpanded) {
|
|
33
|
+
hasBeenExpanded.current = true;
|
|
34
|
+
}
|
|
35
|
+
const handleToggle = () => {
|
|
36
|
+
const next = !isExpanded;
|
|
37
|
+
if (!isControlled) {
|
|
38
|
+
setInternalExpanded(next);
|
|
39
|
+
}
|
|
40
|
+
onToggle?.(next);
|
|
41
|
+
};
|
|
42
|
+
const handleKeyDown = (event) => {
|
|
43
|
+
if (event.key === 'Escape' && isExpanded) {
|
|
44
|
+
event.stopPropagation();
|
|
45
|
+
handleToggle();
|
|
46
|
+
triggerRef.current?.focus();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return (_jsxs("span", { className: cn('eidotter-inline-expand', isExpanded && 'eidotter-inline-expand--expanded', className), onKeyDown: handleKeyDown, ...props, children: [_jsxs(AriaButton, { ref: triggerRef, className: "eidotter-inline-expand__trigger", "aria-expanded": isExpanded, "aria-controls": contentId, onPress: handleToggle, children: [children, _jsx("span", { className: "eidotter-inline-expand__indicator", "aria-hidden": "true", children: isExpanded ? '[-]' : '[+]' })] }), _jsx("span", { id: contentId, className: "eidotter-inline-expand__content", role: "region", inert: !isExpanded, children: _jsxs("span", { className: "eidotter-inline-expand__content-clip", children: [_jsx("span", { className: "eidotter-inline-expand__inner", children: content }), sources.length > 0 && (_jsx("span", { className: "eidotter-inline-expand__sources", role: "list", children: sources.map((source) => (_jsx("span", { className: "eidotter-inline-expand__source-item", role: "listitem", children: _jsxs("a", { href: isSafeUrl(source.url) ? source.url : undefined, className: "eidotter-inline-expand__source-link", target: "_blank", rel: "noopener noreferrer", "aria-label": `${source.title} (opens external website)`, children: [hasBeenExpanded.current && source.favicon && isSafeUrl(source.favicon) && !failedFavicons.has(source.url) ? (_jsx("img", { className: "eidotter-inline-expand__source-favicon", src: source.favicon, alt: "", width: 16, height: 16, decoding: "async", onError: () => setFailedFavicons(prev => new Set(prev).add(source.url)) })) : (_jsx("span", { className: "eidotter-inline-expand__source-icon", "aria-hidden": "true", children: "[\u2192]" })), _jsx("span", { className: "eidotter-inline-expand__source-title", children: source.title })] }) }, source.url))) }))] }) })] }));
|
|
50
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { InlineExpand } from './InlineExpand';
|
|
2
|
-
export type { InlineExpandProps, InlineExpandSource } from './InlineExpand';
|
|
1
|
+
export { InlineExpand } from './InlineExpand.js';
|
|
2
|
+
export type { InlineExpandProps, InlineExpandSource } from './InlineExpand.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InlineExpand } from './InlineExpand.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { InlineExpand } from './components';
|
|
2
|
-
export type { InlineExpandProps, InlineExpandSource } from './components';
|
|
1
|
+
export { InlineExpand } from './components/index.js';
|
|
2
|
+
export type { InlineExpandProps, InlineExpandSource } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InlineExpand } from './components/index.js';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
// Relative paths, hash/query fragments, and standard nav schemes are allowed.
|
|
5
|
+
// Everything else (javascript:, data:, vbscript:, unknown schemes) collapses
|
|
6
|
+
// to a safe "#" sentinel.
|
|
7
|
+
function sanitizeHref(href) {
|
|
8
|
+
const trimmed = href.trim();
|
|
9
|
+
if (trimmed === '')
|
|
10
|
+
return trimmed;
|
|
11
|
+
if (/^[#?/]/.test(trimmed))
|
|
12
|
+
return trimmed;
|
|
13
|
+
const schemeMatch = /^([a-z][a-z0-9+\-.]*):/i.exec(trimmed);
|
|
14
|
+
if (!schemeMatch)
|
|
15
|
+
return trimmed;
|
|
16
|
+
const scheme = schemeMatch[1].toLowerCase();
|
|
17
|
+
const allowed = ['http', 'https', 'mailto', 'tel', 'ftp', 'sms'];
|
|
18
|
+
return allowed.includes(scheme) ? trimmed : '#';
|
|
19
|
+
}
|
|
20
|
+
// Union-merge caller rel tokens with the required safety tokens so
|
|
21
|
+
// consumer-supplied `rel="external"` still gets `noopener noreferrer` when the
|
|
22
|
+
// link opens in a new tab.
|
|
23
|
+
function mergeRel(callerRel, required) {
|
|
24
|
+
if (required.length === 0)
|
|
25
|
+
return callerRel;
|
|
26
|
+
const tokens = new Set((callerRel ?? '').split(/\s+/).map(t => t.trim().toLowerCase()).filter(Boolean));
|
|
27
|
+
for (const token of required)
|
|
28
|
+
tokens.add(token.toLowerCase());
|
|
29
|
+
return Array.from(tokens).join(' ');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* In-flow navigational anchor. Distinct from `<InlineExpand>` — this is a
|
|
33
|
+
* destination, not a disclosure.
|
|
34
|
+
*
|
|
35
|
+
* Rest: dotted amber underline, trailing `▸`.
|
|
36
|
+
* Hover: phosphor inversion — amber background, dark foreground.
|
|
37
|
+
* Visited: dimmed amber (`text.tertiary` role; amber-dim under the default theme).
|
|
38
|
+
* External: opens in a new tab safely, trailing glyph becomes `↗`.
|
|
39
|
+
*
|
|
40
|
+
* Consumer-passed `target="_blank"` is treated as implicit-external for
|
|
41
|
+
* `rel` safety — a `rel` is auto-applied if none is provided, preventing
|
|
42
|
+
* tabnabbing even when the caller doesn't explicitly set `external`.
|
|
43
|
+
*/
|
|
44
|
+
export const InlineLink = forwardRef(({ children, href, showGlyph = true, external = false, className, target, rel, ...props }, ref) => {
|
|
45
|
+
const safeHref = sanitizeHref(href);
|
|
46
|
+
const resolvedTarget = target ?? (external ? '_blank' : undefined);
|
|
47
|
+
// Apply safe rel when the link opens in a new tab for ANY reason —
|
|
48
|
+
// explicit `external` or consumer-supplied `target="_blank"`. Merge with
|
|
49
|
+
// caller rel so `rel="author"` + target=_blank still guards against
|
|
50
|
+
// tabnabbing.
|
|
51
|
+
const opensInNewTab = resolvedTarget === '_blank';
|
|
52
|
+
const resolvedRel = opensInNewTab
|
|
53
|
+
? mergeRel(rel, ['noopener', 'noreferrer'])
|
|
54
|
+
: rel;
|
|
55
|
+
// `external` drives the glyph, but only when the link actually opens in a
|
|
56
|
+
// new tab — `external={true} target="_self"` is an inconsistency we resolve
|
|
57
|
+
// by falling back to the in-flow glyph.
|
|
58
|
+
const glyph = external && opensInNewTab ? '↗' : '▸';
|
|
59
|
+
return (_jsxs("a", { ref: ref, href: safeHref, target: resolvedTarget, rel: resolvedRel, className: cn('eidotter-ilink', external && 'eidotter-ilink--external', className), ...props, children: [_jsx("span", { className: "eidotter-ilink__label", children: children }), showGlyph && (_jsx("span", { className: "eidotter-ilink__glyph", "aria-hidden": "true", children: glyph }))] }));
|
|
60
|
+
});
|
|
61
|
+
InlineLink.displayName = 'InlineLink';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { InlineLink } from './InlineLink';
|
|
2
|
-
export type { InlineLinkProps } from './InlineLink';
|
|
1
|
+
export { InlineLink } from './InlineLink.js';
|
|
2
|
+
export type { InlineLinkProps } from './InlineLink.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InlineLink } from './InlineLink.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { InlineLink } from './components';
|
|
2
|
-
export type { InlineLinkProps } from './components';
|
|
1
|
+
export { InlineLink } from './components/index.js';
|
|
2
|
+
export type { InlineLinkProps } from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InlineLink } 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 { forwardRef } from 'react';
|
|
4
|
+
import { TextField as AriaTextField, Input as AriaInput, Label as AriaLabel, Text as AriaText, } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
const variantClasses = {
|
|
7
|
+
default: 'eidotter-input--default',
|
|
8
|
+
error: 'eidotter-input--error',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* DOS-styled Input with React Aria TextField.
|
|
12
|
+
* Provides automatic label association, description, and error message support.
|
|
13
|
+
*/
|
|
14
|
+
export const Input = forwardRef(({ variant = 'default', label, description, errorMessage, disabled, className, onChange, isRequired, ...props }, ref) => {
|
|
15
|
+
const isInvalid = variant === 'error';
|
|
16
|
+
return (_jsxs(AriaTextField, { isDisabled: disabled, isInvalid: isInvalid, isRequired: isRequired, className: cn('eidotter-text-field', 'flex flex-col gap-1', className), children: [label && (_jsx(AriaLabel, { className: "text-dos-text-brand font-dos text-xs uppercase tracking-wider", children: label })), _jsx(AriaInput, { ref: ref, className: cn('w-full bg-transparent text-dos-text-brand font-dos text-base p-2', 'border-2 border-dos-border-default outline-none box-border', 'eidotter-input', variantClasses[variant] || variantClasses.default, disabled && 'eidotter-input--disabled'), onChange: onChange, ...props }), description && !isInvalid && (_jsx(AriaText, { slot: "description", className: "text-dos-text-muted font-dos text-xs", children: description })), errorMessage && isInvalid && (_jsx(AriaText, { slot: "errorMessage", className: "text-dos-text-error font-dos text-xs", children: errorMessage }))] }));
|
|
17
|
+
});
|
|
18
|
+
Input.displayName = 'Input';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Input } from './Input';
|
|
2
|
-
export type { InputProps } from './Input';
|
|
1
|
+
export { Input } from './Input.js';
|
|
2
|
+
export type { InputProps } from './Input.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Input } from './Input.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './components';
|
|
1
|
+
export * from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/index.js';
|