@raydenui/ui 0.9.7 → 0.10.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/dist/Table-DCNSxua1.d.cts +31 -0
- package/dist/Table-DCNSxua1.d.ts +31 -0
- package/dist/blocks/ApplicationShellBlock.cjs +157 -0
- package/dist/blocks/ApplicationShellBlock.js +154 -0
- package/dist/blocks/CheckoutReviewBlock.cjs +16 -0
- package/dist/blocks/CheckoutReviewBlock.js +13 -0
- package/dist/blocks/CommandPaletteBlock.cjs +334 -0
- package/dist/blocks/CommandPaletteBlock.js +331 -0
- package/dist/blocks/CreateAccountBlock.cjs +147 -0
- package/dist/blocks/CreateAccountBlock.js +143 -0
- package/dist/blocks/EmptyStateBlock.cjs +19 -0
- package/dist/blocks/EmptyStateBlock.js +16 -0
- package/dist/blocks/FeatureOverviewBlock.cjs +54 -0
- package/dist/blocks/FeatureOverviewBlock.js +51 -0
- package/dist/blocks/HeaderBlock.cjs +230 -0
- package/dist/blocks/HeaderBlock.js +227 -0
- package/dist/blocks/KpiOverviewBlock.cjs +63 -0
- package/dist/blocks/KpiOverviewBlock.js +60 -0
- package/dist/blocks/LoginBlock.cjs +66 -0
- package/dist/blocks/LoginBlock.js +63 -0
- package/dist/blocks/NotificationsBlock.cjs +17 -0
- package/dist/blocks/NotificationsBlock.js +14 -0
- package/dist/blocks/PageHeaderBlock.cjs +121 -0
- package/dist/blocks/PageHeaderBlock.js +118 -0
- package/dist/blocks/PricingPlansBlock.cjs +146 -0
- package/dist/blocks/PricingPlansBlock.js +143 -0
- package/dist/blocks/ProductCollectionBlock.cjs +37 -0
- package/dist/blocks/ProductCollectionBlock.js +34 -0
- package/dist/blocks/ProductDetailBlock.cjs +30 -0
- package/dist/blocks/ProductDetailBlock.js +27 -0
- package/dist/blocks/ProductHeroBlock.cjs +83 -0
- package/dist/blocks/ProductHeroBlock.js +80 -0
- package/dist/blocks/ProfileSettingsBlock.cjs +130 -0
- package/dist/blocks/ProfileSettingsBlock.js +126 -0
- package/dist/blocks/QuickSendBlock.cjs +11 -0
- package/dist/blocks/QuickSendBlock.js +8 -0
- package/dist/blocks/RecentTransactionsBlock.cjs +13 -0
- package/dist/blocks/RecentTransactionsBlock.js +10 -0
- package/dist/blocks/SearchableTableBlock.cjs +91 -0
- package/dist/blocks/SearchableTableBlock.js +88 -0
- package/dist/blocks/ShoppingCartBlock.cjs +16 -0
- package/dist/blocks/ShoppingCartBlock.js +13 -0
- package/dist/blocks/SiteFooterBlock.cjs +69 -0
- package/dist/blocks/SiteFooterBlock.js +66 -0
- package/dist/blocks/TableBlock.cjs +20 -0
- package/dist/blocks/TableBlock.js +17 -0
- package/dist/blocks/TaskListBlock.cjs +198 -0
- package/dist/blocks/TaskListBlock.js +195 -0
- package/dist/blocks/WorkspaceSwitcherBlock.cjs +291 -0
- package/dist/blocks/WorkspaceSwitcherBlock.js +288 -0
- package/dist/blocks/commerce.cjs +44 -0
- package/dist/blocks/commerce.js +35 -0
- package/dist/blocks/index.cjs +53 -0
- package/dist/blocks/index.js +24 -0
- package/dist/blocks.d.cts +1820 -0
- package/dist/blocks.d.ts +1820 -0
- package/dist/chart.cjs +13 -0
- package/dist/chart.d.cts +59 -0
- package/dist/chart.d.ts +59 -0
- package/dist/chart.js +5 -0
- package/dist/components/Accordion/Accordion.cjs +94 -0
- package/dist/components/Accordion/Accordion.js +91 -0
- package/dist/components/Accordion/index.cjs +8 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/ActivityFeed/ActivityContent.cjs +40 -0
- package/dist/components/ActivityFeed/ActivityContent.js +37 -0
- package/dist/components/ActivityFeed/ActivityItem.cjs +19 -0
- package/dist/components/ActivityFeed/ActivityItem.js +16 -0
- package/dist/components/ActivityFeed/index.cjs +7 -0
- package/dist/components/ActivityFeed/index.js +2 -0
- package/dist/components/Alert/Alert.cjs +42 -0
- package/dist/components/Alert/Alert.js +39 -0
- package/dist/components/Alert/index.cjs +5 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Avatar/Avatar.cjs +101 -0
- package/dist/components/Avatar/Avatar.js +98 -0
- package/dist/components/Avatar/index.cjs +6 -0
- package/dist/components/Avatar/index.js +1 -0
- package/dist/components/Badge/Badge.cjs +53 -0
- package/dist/components/Badge/Badge.js +50 -0
- package/dist/components/Badge/index.cjs +5 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Banner/Banner.cjs +83 -0
- package/dist/components/Banner/Banner.js +80 -0
- package/dist/components/Banner/index.cjs +5 -0
- package/dist/components/Banner/index.js +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.cjs +31 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +28 -0
- package/dist/components/Breadcrumb/index.cjs +5 -0
- package/dist/components/Breadcrumb/index.js +1 -0
- package/dist/components/Button/Button.cjs +88 -0
- package/dist/components/Button/Button.js +85 -0
- package/dist/components/Button/index.cjs +5 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/ButtonGroup/ButtonGroup.cjs +8 -0
- package/dist/components/ButtonGroup/ButtonGroup.js +5 -0
- package/dist/components/ButtonGroup/ButtonGroupItem.cjs +15 -0
- package/dist/components/ButtonGroup/ButtonGroupItem.js +12 -0
- package/dist/components/ButtonGroup/index.cjs +7 -0
- package/dist/components/ButtonGroup/index.js +2 -0
- package/dist/components/Card/Card.cjs +94 -0
- package/dist/components/Card/Card.js +91 -0
- package/dist/components/Card/index.cjs +9 -0
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Chart/Chart.cjs +160 -0
- package/dist/components/Chart/Chart.js +153 -0
- package/dist/components/Chart/index.cjs +10 -0
- package/dist/components/Chart/index.js +2 -0
- package/dist/components/Chart/theme.cjs +67 -0
- package/dist/components/Chart/theme.js +62 -0
- package/dist/components/Chip/Chip.cjs +18 -0
- package/dist/components/Chip/Chip.js +15 -0
- package/dist/components/Chip/index.cjs +5 -0
- package/dist/components/Chip/index.js +1 -0
- package/dist/components/Counter/Counter.cjs +74 -0
- package/dist/components/Counter/Counter.js +71 -0
- package/dist/components/Counter/index.cjs +6 -0
- package/dist/components/Counter/index.js +1 -0
- package/dist/components/DatePicker/DatePicker.cjs +343 -0
- package/dist/components/DatePicker/DatePicker.js +340 -0
- package/dist/components/DatePicker/index.cjs +5 -0
- package/dist/components/DatePicker/index.js +1 -0
- package/dist/components/Divider/Divider.cjs +31 -0
- package/dist/components/Divider/Divider.js +28 -0
- package/dist/components/Divider/index.cjs +5 -0
- package/dist/components/Divider/index.js +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.cjs +108 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +105 -0
- package/dist/components/DropdownMenu/index.cjs +11 -0
- package/dist/components/DropdownMenu/index.js +1 -0
- package/dist/components/EmptyStateIllustration/EmptyStateIllustration.cjs +42 -0
- package/dist/components/EmptyStateIllustration/EmptyStateIllustration.js +39 -0
- package/dist/components/EmptyStateIllustration/illustrations.cjs +3322 -0
- package/dist/components/EmptyStateIllustration/illustrations.js +3319 -0
- package/dist/components/EmptyStateIllustration/index.cjs +7 -0
- package/dist/components/EmptyStateIllustration/index.js +2 -0
- package/dist/components/FileUpload/FileUpload.cjs +116 -0
- package/dist/components/FileUpload/FileUpload.js +113 -0
- package/dist/components/FileUpload/FileUploadDropZone.cjs +58 -0
- package/dist/components/FileUpload/FileUploadDropZone.js +55 -0
- package/dist/components/FileUpload/FileUploadIcons.cjs +55 -0
- package/dist/components/FileUpload/FileUploadIcons.js +50 -0
- package/dist/components/FileUpload/FileUploadItem.cjs +34 -0
- package/dist/components/FileUpload/FileUploadItem.js +31 -0
- package/dist/components/FileUpload/index.cjs +9 -0
- package/dist/components/FileUpload/index.js +3 -0
- package/dist/components/FormControl/Checkbox.cjs +27 -0
- package/dist/components/FormControl/Checkbox.js +24 -0
- package/dist/components/FormControl/Radio.cjs +15 -0
- package/dist/components/FormControl/Radio.js +12 -0
- package/dist/components/FormControl/Toggle.cjs +15 -0
- package/dist/components/FormControl/Toggle.js +12 -0
- package/dist/components/FormControl/index.cjs +9 -0
- package/dist/components/FormControl/index.js +3 -0
- package/dist/components/Icon/Icon.cjs +70 -0
- package/dist/components/Icon/Icon.js +34 -0
- package/dist/components/Icon/catalog.cjs +1672 -0
- package/dist/components/Icon/catalog.js +1669 -0
- package/dist/components/Icon/icons.cjs +5621 -0
- package/dist/components/Icon/icons.js +5610 -0
- package/dist/components/Icon/index.cjs +8 -0
- package/dist/components/Icon/index.js +2 -0
- package/dist/components/Input/Input.cjs +64 -0
- package/dist/components/Input/Input.js +61 -0
- package/dist/components/Input/index.cjs +5 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/components/MetricsCard/MetricsCard.cjs +107 -0
- package/dist/components/MetricsCard/MetricsCard.js +104 -0
- package/dist/components/MetricsCard/index.cjs +5 -0
- package/dist/components/MetricsCard/index.js +1 -0
- package/dist/components/Modal/Modal.cjs +126 -0
- package/dist/components/Modal/Modal.js +123 -0
- package/dist/components/Modal/index.cjs +5 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/Pagination/Pagination.cjs +42 -0
- package/dist/components/Pagination/Pagination.js +39 -0
- package/dist/components/Pagination/index.cjs +5 -0
- package/dist/components/Pagination/index.js +1 -0
- package/dist/components/ProgressBar/ProgressBar.cjs +34 -0
- package/dist/components/ProgressBar/ProgressBar.js +31 -0
- package/dist/components/ProgressBar/index.cjs +5 -0
- package/dist/components/ProgressBar/index.js +1 -0
- package/dist/components/ProgressCircle/ProgressCircle.cjs +34 -0
- package/dist/components/ProgressCircle/ProgressCircle.js +31 -0
- package/dist/components/ProgressCircle/index.cjs +5 -0
- package/dist/components/ProgressCircle/index.js +1 -0
- package/dist/components/Select/Select.cjs +84 -0
- package/dist/components/Select/Select.js +80 -0
- package/dist/components/Select/SelectOption.cjs +26 -0
- package/dist/components/Select/SelectOption.js +23 -0
- package/dist/components/Select/index.cjs +7 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/SidebarMenu/SidebarMenu.cjs +85 -0
- package/dist/components/SidebarMenu/SidebarMenu.js +81 -0
- package/dist/components/SidebarMenu/SidebarMenuItem.cjs +126 -0
- package/dist/components/SidebarMenu/SidebarMenuItem.js +122 -0
- package/dist/components/SidebarMenu/SidebarMenuSection.cjs +14 -0
- package/dist/components/SidebarMenu/SidebarMenuSection.js +11 -0
- package/dist/components/SidebarMenu/index.cjs +12 -0
- package/dist/components/SidebarMenu/index.js +4 -0
- package/dist/components/Slider/Slider.cjs +161 -0
- package/dist/components/Slider/Slider.js +158 -0
- package/dist/components/Slider/index.cjs +6 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Spinner/Spinner.cjs +93 -0
- package/dist/components/Spinner/Spinner.js +90 -0
- package/dist/components/Spinner/index.cjs +5 -0
- package/dist/components/Spinner/index.js +1 -0
- package/dist/components/Stepper/Stepper.cjs +82 -0
- package/dist/components/Stepper/Stepper.js +79 -0
- package/dist/components/Stepper/index.cjs +7 -0
- package/dist/components/Stepper/index.js +1 -0
- package/dist/components/Table/Table.cjs +25 -0
- package/dist/components/Table/Table.js +22 -0
- package/dist/components/Table/index.cjs +10 -0
- package/dist/components/Table/index.js +1 -0
- package/dist/components/Table/useTableSelection.cjs +60 -0
- package/dist/components/Table/useTableSelection.js +57 -0
- package/dist/components/Tabs/Tab.cjs +70 -0
- package/dist/components/Tabs/Tab.js +67 -0
- package/dist/components/Tabs/Tabs.cjs +133 -0
- package/dist/components/Tabs/Tabs.js +129 -0
- package/dist/components/Tabs/index.cjs +7 -0
- package/dist/components/Tabs/index.js +2 -0
- package/dist/components/Tooltip/Tooltip.cjs +101 -0
- package/dist/components/Tooltip/Tooltip.js +98 -0
- package/dist/components/Tooltip/index.cjs +5 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/context/ThemeContext.cjs +97 -0
- package/dist/context/ThemeContext.js +92 -0
- package/dist/fonts/README.md +13 -0
- package/dist/fonts/hanken-grotesk-cyrillic-ext-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-cyrillic-ext-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-ext-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-ext-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-vietnamese-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-vietnamese-normal.woff2 +0 -0
- package/dist/fonts/hankengrotesk-LICENSE.txt +94 -0
- package/dist/fonts/manrope-LICENSE.txt +93 -0
- package/dist/fonts/manrope-cyrillic-ext-normal.woff2 +0 -0
- package/dist/fonts/manrope-cyrillic-normal.woff2 +0 -0
- package/dist/fonts/manrope-greek-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-ext-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-normal.woff2 +0 -0
- package/dist/fonts/manrope-vietnamese-normal.woff2 +0 -0
- package/dist/fonts.css +148 -0
- package/dist/hooks/form/index.cjs +11 -0
- package/dist/hooks/form/index.js +3 -0
- package/dist/hooks/form/useRaydenFormControl.cjs +81 -0
- package/dist/hooks/form/useRaydenFormControl.js +76 -0
- package/dist/hooks/form/useRaydenInput.cjs +38 -0
- package/dist/hooks/form/useRaydenInput.js +35 -0
- package/dist/hooks/form/useRaydenSelect.cjs +45 -0
- package/dist/hooks/form/useRaydenSelect.js +42 -0
- package/dist/hooks/index.cjs +17 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useBodyScrollLock.cjs +24 -0
- package/dist/hooks/useBodyScrollLock.js +21 -0
- package/dist/hooks/useCollisionAwareSide.cjs +72 -0
- package/dist/hooks/useCollisionAwareSide.js +69 -0
- package/dist/hooks/useControllableValue.cjs +16 -0
- package/dist/hooks/useControllableValue.js +13 -0
- package/dist/hooks/useDismissableLayer.cjs +100 -0
- package/dist/hooks/useDismissableLayer.js +97 -0
- package/dist/hooks/usePopupList.cjs +101 -0
- package/dist/hooks/usePopupList.js +98 -0
- package/dist/icons-8yD7I5jO.d.cts +430 -0
- package/dist/icons-8yD7I5jO.d.ts +430 -0
- package/dist/icons.cjs +2111 -418
- package/dist/icons.d.cts +1256 -429
- package/dist/icons.d.ts +1256 -429
- package/dist/icons.js +2089 -1
- package/dist/index.cjs +128 -15046
- package/dist/index.d.cts +697 -662
- package/dist/index.d.ts +697 -662
- package/dist/index.js +43 -14962
- package/dist/motion/Collapse.cjs +28 -0
- package/dist/motion/Collapse.js +25 -0
- package/dist/motion/MotionProvider.cjs +43 -0
- package/dist/motion/MotionProvider.js +38 -0
- package/dist/motion/Pressable.cjs +46 -0
- package/dist/motion/Pressable.js +43 -0
- package/dist/motion/Reveal.cjs +19 -0
- package/dist/motion/Reveal.js +16 -0
- package/dist/motion/SharedLayout.cjs +46 -0
- package/dist/motion/SharedLayout.js +43 -0
- package/dist/motion/index.cjs +19 -0
- package/dist/motion/index.js +6 -0
- package/dist/motion/presence.cjs +58 -0
- package/dist/motion/presence.js +55 -0
- package/dist/motion/presets.cjs +88 -0
- package/dist/motion/presets.js +84 -0
- package/dist/motion.d.cts +51 -0
- package/dist/motion.d.ts +51 -0
- package/dist/preset.cjs +356 -195
- package/dist/preset.d.cts +111 -32
- package/dist/preset.d.ts +111 -32
- package/dist/preset.js +353 -187
- package/dist/presets-Ba5QndHg.d.cts +144 -0
- package/dist/presets-Ba5QndHg.d.ts +144 -0
- package/dist/styles.css +1 -1
- package/dist/utils/cn.cjs +38 -0
- package/dist/utils/cn.js +35 -0
- package/dist/utils/resolveIcon.cjs +18 -0
- package/dist/utils/resolveIcon.js +15 -0
- package/package.json +79 -21
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Children, isValidElement, createContext, useCallback, useEffect, useLayoutEffect, useContext, useMemo, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../../utils/cn.js";
|
|
4
|
+
import { SharedLayout } from "../../motion/SharedLayout.js";
|
|
5
|
+
import { useRaydenMotion } from "../../motion/MotionProvider.js";
|
|
6
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
7
|
+
const TabsContext = createContext(null);
|
|
8
|
+
export function useTabsContext() {
|
|
9
|
+
const ctx = useContext(TabsContext);
|
|
10
|
+
if (!ctx)
|
|
11
|
+
throw new Error("Tab must be used within Tabs");
|
|
12
|
+
return ctx;
|
|
13
|
+
}
|
|
14
|
+
export function Tabs({ motion = false, variant = "line", size = "sm", orientation = "horizontal", value, defaultValue = "", onValueChange, children, className, }) {
|
|
15
|
+
const listRef = useRef(null);
|
|
16
|
+
const [indicator, setIndicator] = useState(null);
|
|
17
|
+
const { preset } = useRaydenMotion(motion);
|
|
18
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
19
|
+
const enabledValues = [];
|
|
20
|
+
function collect(nodes) {
|
|
21
|
+
Children.forEach(nodes, (node) => {
|
|
22
|
+
if (!isValidElement(node))
|
|
23
|
+
return;
|
|
24
|
+
if (typeof node.props.value === "string") {
|
|
25
|
+
if (!node.props.disabled)
|
|
26
|
+
enabledValues.push(node.props.value);
|
|
27
|
+
}
|
|
28
|
+
else if (node.props.children)
|
|
29
|
+
collect(node.props.children);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
collect(children);
|
|
33
|
+
const requestedValue = value ?? internalValue;
|
|
34
|
+
const activeValue = enabledValues.includes(requestedValue)
|
|
35
|
+
? requestedValue
|
|
36
|
+
: (enabledValues[0] ?? "");
|
|
37
|
+
const tabsRef = useRef(new Map());
|
|
38
|
+
const onSelect = useCallback((val) => {
|
|
39
|
+
if (value === undefined)
|
|
40
|
+
setInternalValue(val);
|
|
41
|
+
onValueChange?.(val);
|
|
42
|
+
}, [value, onValueChange]);
|
|
43
|
+
const registerTab = useCallback((tabValue, element) => {
|
|
44
|
+
if (element) {
|
|
45
|
+
tabsRef.current.set(tabValue, element);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
tabsRef.current.delete(tabValue);
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
51
|
+
const isVertical = orientation === "vertical";
|
|
52
|
+
const arrowNext = isVertical ? "ArrowDown" : "ArrowRight";
|
|
53
|
+
const arrowPrev = isVertical ? "ArrowUp" : "ArrowLeft";
|
|
54
|
+
useBrowserLayoutEffect(() => {
|
|
55
|
+
const list = listRef.current;
|
|
56
|
+
if (!motion || !list)
|
|
57
|
+
return;
|
|
58
|
+
const measure = () => {
|
|
59
|
+
const selected = Array.from(list.querySelectorAll('[role="tab"]')).find((tab) => tab.getAttribute("aria-selected") === "true");
|
|
60
|
+
if (!selected) {
|
|
61
|
+
setIndicator(null);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const base = {
|
|
65
|
+
left: selected.offsetLeft,
|
|
66
|
+
top: selected.offsetTop,
|
|
67
|
+
width: selected.offsetWidth,
|
|
68
|
+
height: selected.offsetHeight,
|
|
69
|
+
};
|
|
70
|
+
if (variant === "line") {
|
|
71
|
+
if (isVertical) {
|
|
72
|
+
base.left += base.width - 2;
|
|
73
|
+
base.width = 2;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
base.top += base.height - 2;
|
|
77
|
+
base.height = 2;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
setIndicator((previous) => previous &&
|
|
81
|
+
Object.keys(base).every((key) => base[key] === previous[key])
|
|
82
|
+
? previous
|
|
83
|
+
: base);
|
|
84
|
+
};
|
|
85
|
+
measure();
|
|
86
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
87
|
+
observer?.observe(list);
|
|
88
|
+
Array.from(list.children).forEach((child) => observer?.observe(child));
|
|
89
|
+
return () => observer?.disconnect();
|
|
90
|
+
}, [activeValue, motion, variant, size, isVertical, children]);
|
|
91
|
+
const handleKeyDown = (e) => {
|
|
92
|
+
const tabs = Array.from(tabsRef.current.entries())
|
|
93
|
+
.filter(([, el]) => !el.disabled)
|
|
94
|
+
.sort((a, b) => a[1].compareDocumentPosition(b[1]) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1)
|
|
95
|
+
.map(([val, el]) => ({ value: val, element: el }));
|
|
96
|
+
if (tabs.length === 0)
|
|
97
|
+
return;
|
|
98
|
+
const currentIndex = tabs.findIndex((t) => t.element === document.activeElement);
|
|
99
|
+
let nextIndex;
|
|
100
|
+
switch (e.key) {
|
|
101
|
+
case arrowNext:
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
nextIndex = currentIndex < tabs.length - 1 ? currentIndex + 1 : 0;
|
|
104
|
+
break;
|
|
105
|
+
case arrowPrev:
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
nextIndex = currentIndex > 0 ? currentIndex - 1 : tabs.length - 1;
|
|
108
|
+
break;
|
|
109
|
+
case "Home":
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
nextIndex = 0;
|
|
112
|
+
break;
|
|
113
|
+
case "End":
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
nextIndex = tabs.length - 1;
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const nextTab = tabs[nextIndex];
|
|
121
|
+
if (nextTab) {
|
|
122
|
+
nextTab.element.focus();
|
|
123
|
+
onSelect(nextTab.value);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const contextValue = useMemo(() => ({ activeValue, onSelect, variant, size, orientation, registerTab, motion }), [activeValue, onSelect, variant, size, orientation, registerTab, motion]);
|
|
127
|
+
return (_jsx(TabsContext.Provider, { value: contextValue, children: _jsxs("div", { ref: listRef, "data-rayden-motion": motion ? preset : undefined, className: cn("inline-flex", motion && "relative isolate", isVertical ? "flex-col" : "", variant === "line" && !isVertical && "border-b border-grey-200", variant === "line" && isVertical && "border-r border-grey-200", variant === "pill" && (isVertical ? "gap-1" : "gap-1"), variant === "segmented" &&
|
|
128
|
+
"border border-grey-100 bg-grey-50 rounded-lg p-0.5 gap-0.5 overflow-hidden", className), role: "tablist", "aria-orientation": orientation, onKeyDown: handleKeyDown, children: [motion && indicator && (_jsx(SharedLayout, { "aria-hidden": "true", "data-rayden-tab-indicator": "", motion: motion, layoutKey: `${activeValue}:${indicator.left}:${indicator.top}:${indicator.width}:${indicator.height}`, className: cn("pointer-events-none absolute", variant === "line" ? "bg-primary-400" : "bg-primary-50", variant === "pill" && "rounded-full", variant === "segmented" && "rounded-md"), style: indicator })), children] }) }));
|
|
129
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Tab = exports.Tabs = void 0;
|
|
4
|
+
var Tabs_1 = require("./Tabs.cjs");
|
|
5
|
+
Object.defineProperty(exports, "Tabs", { enumerable: true, get: function () { return Tabs_1.Tabs; } });
|
|
6
|
+
var Tab_1 = require("./Tab.cjs");
|
|
7
|
+
Object.defineProperty(exports, "Tab", { enumerable: true, get: function () { return Tab_1.Tab; } });
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Tooltip = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const useControllableValue_1 = require("../../hooks/useControllableValue.cjs");
|
|
7
|
+
const useDismissableLayer_1 = require("../../hooks/useDismissableLayer.cjs");
|
|
8
|
+
const cn_1 = require("../../utils/cn.cjs");
|
|
9
|
+
const useCollisionAwareSide_1 = require("../../hooks/useCollisionAwareSide.cjs");
|
|
10
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? react_1.useEffect : react_1.useLayoutEffect;
|
|
11
|
+
/** With children, provides a hover/focus tooltip (or a click popover for actions).
|
|
12
|
+
* Without children, retains the original standalone panel API. */
|
|
13
|
+
exports.Tooltip = (0, react_1.forwardRef)(({ theme = "light", position = "top-left", placement, title, content, children, delay = 0, open: controlledOpen, defaultOpen = false, onOpenChange, onClose, primaryAction, secondaryAction, className, ...rest }, ref) => {
|
|
14
|
+
const id = (0, react_1.useId)();
|
|
15
|
+
const [open, changeOpen] = (0, useControllableValue_1.useControllableValue)(controlledOpen, defaultOpen, onOpenChange);
|
|
16
|
+
const timer = (0, react_1.useRef)(undefined);
|
|
17
|
+
const wrapper = (0, react_1.useRef)(null);
|
|
18
|
+
const panelRef = (0, react_1.useRef)(null);
|
|
19
|
+
const interactive = !!(onClose || primaryAction || secondaryAction);
|
|
20
|
+
const preferredSide = (placement ?? position.split("-")[0]);
|
|
21
|
+
// Fixed side classes put the panel off-screen at a viewport edge; flip when the
|
|
22
|
+
// preferred side does not fit.
|
|
23
|
+
const side = (0, useCollisionAwareSide_1.useCollisionAwareSide)(preferredSide, open, wrapper, panelRef);
|
|
24
|
+
const setOpen = (next) => {
|
|
25
|
+
clearTimeout(timer.current);
|
|
26
|
+
changeOpen(next);
|
|
27
|
+
};
|
|
28
|
+
const close = () => {
|
|
29
|
+
setOpen(false);
|
|
30
|
+
if (children && interactive)
|
|
31
|
+
wrapper.current?.querySelector("button, a[href], [tabindex]")?.focus();
|
|
32
|
+
onClose?.();
|
|
33
|
+
};
|
|
34
|
+
(0, react_1.useEffect)(() => () => clearTimeout(timer.current), []);
|
|
35
|
+
const hasPanel = !!children;
|
|
36
|
+
// Focus the panel only on the closed -> open transition, never on a rerender.
|
|
37
|
+
const wasOpen = (0, react_1.useRef)(false);
|
|
38
|
+
useBrowserLayoutEffect(() => {
|
|
39
|
+
if (open && !wasOpen.current && hasPanel && interactive) {
|
|
40
|
+
panelRef.current?.focus();
|
|
41
|
+
}
|
|
42
|
+
wasOpen.current = open;
|
|
43
|
+
}, [open, hasPanel, interactive]);
|
|
44
|
+
(0, useDismissableLayer_1.useDismissableLayer)({
|
|
45
|
+
open: open && hasPanel,
|
|
46
|
+
containerRef: wrapper,
|
|
47
|
+
onDismiss: (reason) => {
|
|
48
|
+
if (reason === "escape")
|
|
49
|
+
close();
|
|
50
|
+
else
|
|
51
|
+
setOpen(false);
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
const panel = ((0, jsx_runtime_1.jsxs)("div", { id: id, ref: panelRef, role: interactive ? "dialog" : "tooltip", "aria-label": interactive ? (title ?? "More information") : undefined, tabIndex: interactive ? -1 : undefined, className: (0, cn_1.cn)("flex max-w-[min(20rem,calc(100vw-2rem))] flex-col gap-4 rounded-lg border p-4 text-sm shadow-soft-sm", theme === "dark"
|
|
55
|
+
? "bg-tooltip-dark text-tooltip-dark-text border-tooltip-dark"
|
|
56
|
+
: "bg-surface text-on-surface border-grey-200"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1 space-y-1", children: [title && (0, jsx_runtime_1.jsx)("p", { className: "font-semibold", children: title }), (0, jsx_runtime_1.jsx)("div", { children: content })] }), onClose && ((0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Close", onClick: close, className: "rounded px-1 focus-visible:outline-2 focus-visible:outline-current", children: "\u00D7" }))] }), (primaryAction || secondaryAction) && ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [secondaryAction && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "rounded font-semibold underline focus-visible:outline-2 focus-visible:outline-current", onClick: secondaryAction.onClick, children: secondaryAction.label })), primaryAction && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "rounded font-semibold underline focus-visible:outline-2 focus-visible:outline-current", onClick: primaryAction.onClick, children: primaryAction.label }))] }))] }));
|
|
57
|
+
const trigger = (0, react_1.isValidElement)(children)
|
|
58
|
+
? (0, react_1.cloneElement)(children, {
|
|
59
|
+
...(interactive
|
|
60
|
+
? {
|
|
61
|
+
"aria-haspopup": "dialog",
|
|
62
|
+
"aria-expanded": open,
|
|
63
|
+
"aria-controls": open ? id : undefined,
|
|
64
|
+
}
|
|
65
|
+
: {
|
|
66
|
+
"aria-describedby": [children.props["aria-describedby"], open ? id : undefined]
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.join(" ") || undefined,
|
|
69
|
+
}),
|
|
70
|
+
onClick: (event) => {
|
|
71
|
+
children.props.onClick?.(event);
|
|
72
|
+
if (interactive && !event.defaultPrevented)
|
|
73
|
+
setOpen(!open);
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
: children;
|
|
77
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ...rest, ref: (node) => {
|
|
78
|
+
wrapper.current = node;
|
|
79
|
+
if (typeof ref === "function")
|
|
80
|
+
ref(node);
|
|
81
|
+
else if (ref)
|
|
82
|
+
ref.current = node;
|
|
83
|
+
}, className: (0, cn_1.cn)("relative inline-flex", className), onMouseEnter: (event) => {
|
|
84
|
+
rest.onMouseEnter?.(event);
|
|
85
|
+
if (children && !interactive) {
|
|
86
|
+
clearTimeout(timer.current);
|
|
87
|
+
timer.current = setTimeout(() => setOpen(true), delay);
|
|
88
|
+
}
|
|
89
|
+
}, onMouseLeave: (event) => {
|
|
90
|
+
rest.onMouseLeave?.(event);
|
|
91
|
+
if (children && !interactive && !wrapper.current?.contains(document.activeElement))
|
|
92
|
+
setOpen(false);
|
|
93
|
+
}, onFocus: (event) => {
|
|
94
|
+
rest.onFocus?.(event);
|
|
95
|
+
if (children && !interactive)
|
|
96
|
+
setOpen(true);
|
|
97
|
+
}, children: [trigger, children
|
|
98
|
+
? open && ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("absolute z-50 w-max max-w-[calc(100vw-2rem)]", side === "top" && "bottom-full left-1/2 -translate-x-1/2 pb-2", side === "bottom" && "top-full left-1/2 -translate-x-1/2 pt-2", side === "left" && "right-full top-1/2 -translate-y-1/2 pr-2", side === "right" && "left-full top-1/2 -translate-y-1/2 pl-2"), children: panel }))
|
|
99
|
+
: panel] }));
|
|
100
|
+
});
|
|
101
|
+
exports.Tooltip.displayName = "Tooltip";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, forwardRef, isValidElement, useEffect, useId, useLayoutEffect, useRef, } from "react";
|
|
3
|
+
import { useControllableValue } from "../../hooks/useControllableValue.js";
|
|
4
|
+
import { useDismissableLayer } from "../../hooks/useDismissableLayer.js";
|
|
5
|
+
import { cn } from "../../utils/cn.js";
|
|
6
|
+
import { useCollisionAwareSide } from "../../hooks/useCollisionAwareSide.js";
|
|
7
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
8
|
+
/** With children, provides a hover/focus tooltip (or a click popover for actions).
|
|
9
|
+
* Without children, retains the original standalone panel API. */
|
|
10
|
+
export const Tooltip = forwardRef(({ theme = "light", position = "top-left", placement, title, content, children, delay = 0, open: controlledOpen, defaultOpen = false, onOpenChange, onClose, primaryAction, secondaryAction, className, ...rest }, ref) => {
|
|
11
|
+
const id = useId();
|
|
12
|
+
const [open, changeOpen] = useControllableValue(controlledOpen, defaultOpen, onOpenChange);
|
|
13
|
+
const timer = useRef(undefined);
|
|
14
|
+
const wrapper = useRef(null);
|
|
15
|
+
const panelRef = useRef(null);
|
|
16
|
+
const interactive = !!(onClose || primaryAction || secondaryAction);
|
|
17
|
+
const preferredSide = (placement ?? position.split("-")[0]);
|
|
18
|
+
// Fixed side classes put the panel off-screen at a viewport edge; flip when the
|
|
19
|
+
// preferred side does not fit.
|
|
20
|
+
const side = useCollisionAwareSide(preferredSide, open, wrapper, panelRef);
|
|
21
|
+
const setOpen = (next) => {
|
|
22
|
+
clearTimeout(timer.current);
|
|
23
|
+
changeOpen(next);
|
|
24
|
+
};
|
|
25
|
+
const close = () => {
|
|
26
|
+
setOpen(false);
|
|
27
|
+
if (children && interactive)
|
|
28
|
+
wrapper.current?.querySelector("button, a[href], [tabindex]")?.focus();
|
|
29
|
+
onClose?.();
|
|
30
|
+
};
|
|
31
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
32
|
+
const hasPanel = !!children;
|
|
33
|
+
// Focus the panel only on the closed -> open transition, never on a rerender.
|
|
34
|
+
const wasOpen = useRef(false);
|
|
35
|
+
useBrowserLayoutEffect(() => {
|
|
36
|
+
if (open && !wasOpen.current && hasPanel && interactive) {
|
|
37
|
+
panelRef.current?.focus();
|
|
38
|
+
}
|
|
39
|
+
wasOpen.current = open;
|
|
40
|
+
}, [open, hasPanel, interactive]);
|
|
41
|
+
useDismissableLayer({
|
|
42
|
+
open: open && hasPanel,
|
|
43
|
+
containerRef: wrapper,
|
|
44
|
+
onDismiss: (reason) => {
|
|
45
|
+
if (reason === "escape")
|
|
46
|
+
close();
|
|
47
|
+
else
|
|
48
|
+
setOpen(false);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
const panel = (_jsxs("div", { id: id, ref: panelRef, role: interactive ? "dialog" : "tooltip", "aria-label": interactive ? (title ?? "More information") : undefined, tabIndex: interactive ? -1 : undefined, className: cn("flex max-w-[min(20rem,calc(100vw-2rem))] flex-col gap-4 rounded-lg border p-4 text-sm shadow-soft-sm", theme === "dark"
|
|
52
|
+
? "bg-tooltip-dark text-tooltip-dark-text border-tooltip-dark"
|
|
53
|
+
: "bg-surface text-on-surface border-grey-200"), children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [title && _jsx("p", { className: "font-semibold", children: title }), _jsx("div", { children: content })] }), onClose && (_jsx("button", { type: "button", "aria-label": "Close", onClick: close, className: "rounded px-1 focus-visible:outline-2 focus-visible:outline-current", children: "\u00D7" }))] }), (primaryAction || secondaryAction) && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [secondaryAction && (_jsx("button", { type: "button", className: "rounded font-semibold underline focus-visible:outline-2 focus-visible:outline-current", onClick: secondaryAction.onClick, children: secondaryAction.label })), primaryAction && (_jsx("button", { type: "button", className: "rounded font-semibold underline focus-visible:outline-2 focus-visible:outline-current", onClick: primaryAction.onClick, children: primaryAction.label }))] }))] }));
|
|
54
|
+
const trigger = isValidElement(children)
|
|
55
|
+
? cloneElement(children, {
|
|
56
|
+
...(interactive
|
|
57
|
+
? {
|
|
58
|
+
"aria-haspopup": "dialog",
|
|
59
|
+
"aria-expanded": open,
|
|
60
|
+
"aria-controls": open ? id : undefined,
|
|
61
|
+
}
|
|
62
|
+
: {
|
|
63
|
+
"aria-describedby": [children.props["aria-describedby"], open ? id : undefined]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(" ") || undefined,
|
|
66
|
+
}),
|
|
67
|
+
onClick: (event) => {
|
|
68
|
+
children.props.onClick?.(event);
|
|
69
|
+
if (interactive && !event.defaultPrevented)
|
|
70
|
+
setOpen(!open);
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
: children;
|
|
74
|
+
return (_jsxs("div", { ...rest, ref: (node) => {
|
|
75
|
+
wrapper.current = node;
|
|
76
|
+
if (typeof ref === "function")
|
|
77
|
+
ref(node);
|
|
78
|
+
else if (ref)
|
|
79
|
+
ref.current = node;
|
|
80
|
+
}, className: cn("relative inline-flex", className), onMouseEnter: (event) => {
|
|
81
|
+
rest.onMouseEnter?.(event);
|
|
82
|
+
if (children && !interactive) {
|
|
83
|
+
clearTimeout(timer.current);
|
|
84
|
+
timer.current = setTimeout(() => setOpen(true), delay);
|
|
85
|
+
}
|
|
86
|
+
}, onMouseLeave: (event) => {
|
|
87
|
+
rest.onMouseLeave?.(event);
|
|
88
|
+
if (children && !interactive && !wrapper.current?.contains(document.activeElement))
|
|
89
|
+
setOpen(false);
|
|
90
|
+
}, onFocus: (event) => {
|
|
91
|
+
rest.onFocus?.(event);
|
|
92
|
+
if (children && !interactive)
|
|
93
|
+
setOpen(true);
|
|
94
|
+
}, children: [trigger, children
|
|
95
|
+
? open && (_jsx("div", { className: cn("absolute z-50 w-max max-w-[calc(100vw-2rem)]", side === "top" && "bottom-full left-1/2 -translate-x-1/2 pb-2", side === "bottom" && "top-full left-1/2 -translate-x-1/2 pt-2", side === "left" && "right-full top-1/2 -translate-y-1/2 pr-2", side === "right" && "left-full top-1/2 -translate-y-1/2 pl-2"), children: panel }))
|
|
96
|
+
: panel] }));
|
|
97
|
+
});
|
|
98
|
+
Tooltip.displayName = "Tooltip";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Tooltip } from "./Tooltip.js";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ThemeProvider = ThemeProvider;
|
|
5
|
+
exports.useTheme = useTheme;
|
|
6
|
+
exports.useResolvedTheme = useResolvedTheme;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const ThemeContext = (0, react_1.createContext)(null);
|
|
10
|
+
const STORAGE_KEY = "rayden-theme";
|
|
11
|
+
function getSystemTheme() {
|
|
12
|
+
if (typeof window === "undefined")
|
|
13
|
+
return "light";
|
|
14
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
15
|
+
}
|
|
16
|
+
function getStoredTheme(storageKey) {
|
|
17
|
+
if (typeof window === "undefined")
|
|
18
|
+
return null;
|
|
19
|
+
let stored;
|
|
20
|
+
try {
|
|
21
|
+
stored = localStorage.getItem(storageKey);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Storage can throw in a private window or when site data is blocked.
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
if (stored === "light" || stored === "dark" || stored === "system")
|
|
28
|
+
return stored;
|
|
29
|
+
// null means "no stored preference", which is distinct from a stored "system".
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
function ThemeProvider({ children, defaultTheme = "system", storageKey = STORAGE_KEY, disableSystemTheme = false, }) {
|
|
33
|
+
const [theme, setThemeState] = (0, react_1.useState)(() => {
|
|
34
|
+
if (typeof window === "undefined")
|
|
35
|
+
return defaultTheme;
|
|
36
|
+
return getStoredTheme(storageKey) ?? defaultTheme;
|
|
37
|
+
});
|
|
38
|
+
const [systemTheme, setSystemTheme] = (0, react_1.useState)(() => getSystemTheme());
|
|
39
|
+
// Listen for system theme changes
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
41
|
+
if (disableSystemTheme)
|
|
42
|
+
return;
|
|
43
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
44
|
+
const handleChange = (e) => {
|
|
45
|
+
setSystemTheme(e.matches ? "dark" : "light");
|
|
46
|
+
};
|
|
47
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
48
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
49
|
+
}, [disableSystemTheme]);
|
|
50
|
+
// Resolve the actual theme
|
|
51
|
+
const resolvedTheme = (0, react_1.useMemo)(() => {
|
|
52
|
+
if (theme === "system") {
|
|
53
|
+
return disableSystemTheme ? "light" : systemTheme;
|
|
54
|
+
}
|
|
55
|
+
return theme;
|
|
56
|
+
}, [theme, systemTheme, disableSystemTheme]);
|
|
57
|
+
// Apply theme to document
|
|
58
|
+
(0, react_1.useEffect)(() => {
|
|
59
|
+
const root = document.documentElement;
|
|
60
|
+
root.classList.remove("light", "dark");
|
|
61
|
+
root.classList.add(resolvedTheme);
|
|
62
|
+
}, [resolvedTheme]);
|
|
63
|
+
const setTheme = (0, react_1.useCallback)((newTheme) => {
|
|
64
|
+
setThemeState(newTheme);
|
|
65
|
+
try {
|
|
66
|
+
localStorage.setItem(storageKey, newTheme);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Persisting is best-effort; the in-memory theme still applies.
|
|
70
|
+
}
|
|
71
|
+
}, [storageKey]);
|
|
72
|
+
const toggleTheme = (0, react_1.useCallback)(() => {
|
|
73
|
+
setTheme(resolvedTheme === "light" ? "dark" : "light");
|
|
74
|
+
}, [resolvedTheme, setTheme]);
|
|
75
|
+
const value = (0, react_1.useMemo)(() => ({
|
|
76
|
+
theme,
|
|
77
|
+
resolvedTheme,
|
|
78
|
+
setTheme,
|
|
79
|
+
toggleTheme,
|
|
80
|
+
}), [theme, resolvedTheme, setTheme, toggleTheme]);
|
|
81
|
+
return (0, jsx_runtime_1.jsx)(ThemeContext.Provider, { value: value, children: children });
|
|
82
|
+
}
|
|
83
|
+
function useTheme() {
|
|
84
|
+
const context = (0, react_1.useContext)(ThemeContext);
|
|
85
|
+
if (!context) {
|
|
86
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
87
|
+
}
|
|
88
|
+
return context;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Hook that returns only the resolved theme (light or dark).
|
|
92
|
+
* Useful for components that just need to know the current theme.
|
|
93
|
+
*/
|
|
94
|
+
function useResolvedTheme() {
|
|
95
|
+
const { resolvedTheme } = useTheme();
|
|
96
|
+
return resolvedTheme;
|
|
97
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
|
|
4
|
+
const ThemeContext = createContext(null);
|
|
5
|
+
const STORAGE_KEY = "rayden-theme";
|
|
6
|
+
function getSystemTheme() {
|
|
7
|
+
if (typeof window === "undefined")
|
|
8
|
+
return "light";
|
|
9
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
10
|
+
}
|
|
11
|
+
function getStoredTheme(storageKey) {
|
|
12
|
+
if (typeof window === "undefined")
|
|
13
|
+
return null;
|
|
14
|
+
let stored;
|
|
15
|
+
try {
|
|
16
|
+
stored = localStorage.getItem(storageKey);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Storage can throw in a private window or when site data is blocked.
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (stored === "light" || stored === "dark" || stored === "system")
|
|
23
|
+
return stored;
|
|
24
|
+
// null means "no stored preference", which is distinct from a stored "system".
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
export function ThemeProvider({ children, defaultTheme = "system", storageKey = STORAGE_KEY, disableSystemTheme = false, }) {
|
|
28
|
+
const [theme, setThemeState] = useState(() => {
|
|
29
|
+
if (typeof window === "undefined")
|
|
30
|
+
return defaultTheme;
|
|
31
|
+
return getStoredTheme(storageKey) ?? defaultTheme;
|
|
32
|
+
});
|
|
33
|
+
const [systemTheme, setSystemTheme] = useState(() => getSystemTheme());
|
|
34
|
+
// Listen for system theme changes
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (disableSystemTheme)
|
|
37
|
+
return;
|
|
38
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
39
|
+
const handleChange = (e) => {
|
|
40
|
+
setSystemTheme(e.matches ? "dark" : "light");
|
|
41
|
+
};
|
|
42
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
43
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
44
|
+
}, [disableSystemTheme]);
|
|
45
|
+
// Resolve the actual theme
|
|
46
|
+
const resolvedTheme = useMemo(() => {
|
|
47
|
+
if (theme === "system") {
|
|
48
|
+
return disableSystemTheme ? "light" : systemTheme;
|
|
49
|
+
}
|
|
50
|
+
return theme;
|
|
51
|
+
}, [theme, systemTheme, disableSystemTheme]);
|
|
52
|
+
// Apply theme to document
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const root = document.documentElement;
|
|
55
|
+
root.classList.remove("light", "dark");
|
|
56
|
+
root.classList.add(resolvedTheme);
|
|
57
|
+
}, [resolvedTheme]);
|
|
58
|
+
const setTheme = useCallback((newTheme) => {
|
|
59
|
+
setThemeState(newTheme);
|
|
60
|
+
try {
|
|
61
|
+
localStorage.setItem(storageKey, newTheme);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Persisting is best-effort; the in-memory theme still applies.
|
|
65
|
+
}
|
|
66
|
+
}, [storageKey]);
|
|
67
|
+
const toggleTheme = useCallback(() => {
|
|
68
|
+
setTheme(resolvedTheme === "light" ? "dark" : "light");
|
|
69
|
+
}, [resolvedTheme, setTheme]);
|
|
70
|
+
const value = useMemo(() => ({
|
|
71
|
+
theme,
|
|
72
|
+
resolvedTheme,
|
|
73
|
+
setTheme,
|
|
74
|
+
toggleTheme,
|
|
75
|
+
}), [theme, resolvedTheme, setTheme, toggleTheme]);
|
|
76
|
+
return _jsx(ThemeContext.Provider, { value: value, children: children });
|
|
77
|
+
}
|
|
78
|
+
export function useTheme() {
|
|
79
|
+
const context = useContext(ThemeContext);
|
|
80
|
+
if (!context) {
|
|
81
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
82
|
+
}
|
|
83
|
+
return context;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Hook that returns only the resolved theme (light or dark).
|
|
87
|
+
* Useful for components that just need to know the current theme.
|
|
88
|
+
*/
|
|
89
|
+
export function useResolvedTheme() {
|
|
90
|
+
const { resolvedTheme } = useTheme();
|
|
91
|
+
return resolvedTheme;
|
|
92
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Rayden webfonts
|
|
2
|
+
|
|
3
|
+
Downloaded from the Google Fonts CSS API on 2026-09-22 using a modern Chromium user agent:
|
|
4
|
+
|
|
5
|
+
https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900;1,100..900&family=Manrope:wght@200..800&display=swap
|
|
6
|
+
|
|
7
|
+
Files are unmodified WOFF2 subsets from fonts.gstatic.com: Hanken Grotesk v12 (normal and italic, weights 100–900), Manrope v20 (normal, weights 200–800). Unicode ranges in ../fonts.css control subset loading. Google Fonts' original SIL Open Font License files are included alongside the assets.
|
|
8
|
+
|
|
9
|
+
Upstream sources:
|
|
10
|
+
- https://github.com/google/fonts/tree/main/ofl/hankengrotesk
|
|
11
|
+
- https://github.com/google/fonts/tree/main/ofl/manrope
|
|
12
|
+
|
|
13
|
+
These assets are copied to dist/fonts during the library build. Consumers opt in with @raydenui/ui/fonts.css. SF Mono and Menlo are local fallbacks and are not bundled.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|