@kadoui/react 1.0.0 → 1.0.1

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.
Files changed (179) hide show
  1. package/README.md +1 -0
  2. package/dist/components/AccessNavigation/AccessNavigation.d.ts.map +1 -1
  3. package/dist/components/AccessNavigation/AccessNavigation.jsx +1 -1
  4. package/dist/components/Accordion/AccordionBody.jsx +1 -1
  5. package/dist/components/Affix/Affix.jsx +1 -1
  6. package/dist/components/Breadcrumbs/BreadcrumbsItem.jsx +1 -1
  7. package/dist/components/Breadcrumbs/BreadcrumbsRoot.jsx +1 -1
  8. package/dist/components/Carousel/CarouselContainer.jsx +1 -1
  9. package/dist/components/Carousel/CarouselRoot.jsx +1 -1
  10. package/dist/components/ContextMenu/ContextMenuContent.d.ts.map +1 -1
  11. package/dist/components/ContextMenu/ContextMenuContent.jsx +2 -1
  12. package/dist/components/ContextMenu/ContextMenuRoot.d.ts.map +1 -1
  13. package/dist/components/ContextMenu/ContextMenuRoot.jsx +1 -1
  14. package/dist/components/Drawer/DrawerBody.jsx +1 -1
  15. package/dist/components/Drawer/DrawerPortal.jsx +1 -1
  16. package/dist/components/Drawer/DrawerRoot.jsx +1 -1
  17. package/dist/components/Dropdown/DropdownMenu.d.ts.map +1 -1
  18. package/dist/components/Dropdown/DropdownMenu.jsx +1 -1
  19. package/dist/components/Dropdown/DropdownRoot.d.ts.map +1 -1
  20. package/dist/components/Dropdown/DropdownRoot.jsx +2 -1
  21. package/dist/components/LinkLoader/LinkLoader.jsx +1 -1
  22. package/dist/components/Modal/ModalBody.jsx +1 -1
  23. package/dist/components/Modal/ModalContent.jsx +1 -1
  24. package/dist/components/Modal/ModalHeader.jsx +1 -1
  25. package/dist/components/Modal/ModalPortal.jsx +1 -1
  26. package/dist/components/Modal/ModalRoot.d.ts.map +1 -1
  27. package/dist/components/Modal/ModalRoot.jsx +1 -1
  28. package/dist/components/Otp/OtpInputs.jsx +1 -1
  29. package/dist/components/Otp/OtpRoot.jsx +1 -1
  30. package/dist/components/Progress/ProgressBar.jsx +1 -1
  31. package/dist/components/Progress/ProgressRoot.jsx +1 -1
  32. package/dist/components/Rating/RatingItems.jsx +1 -1
  33. package/dist/components/Rating/RatingRoot.jsx +1 -1
  34. package/dist/components/Sheet/SheetBody.jsx +1 -1
  35. package/dist/components/Sheet/SheetContent.jsx +1 -1
  36. package/dist/components/Sheet/SheetHeader.jsx +1 -1
  37. package/dist/components/Sheet/SheetPortal.jsx +1 -1
  38. package/dist/components/ShowMore/ShowMoreContent.jsx +1 -1
  39. package/dist/components/ShowMore/ShowMoreFade.jsx +1 -1
  40. package/dist/components/ShowMore/ShowMoreRoot.jsx +1 -1
  41. package/dist/components/ShowMore/ShowMoreTrigger.jsx +1 -1
  42. package/dist/components/Slide/SlideContent.jsx +1 -1
  43. package/dist/components/Slide/SlideHeader.jsx +1 -1
  44. package/dist/components/Slide/SlidePortal.jsx +1 -1
  45. package/dist/components/Spoiler/Spoiler.jsx +1 -1
  46. package/dist/components/Steps/StepsControls.jsx +1 -1
  47. package/dist/components/Tabs/TabsList.jsx +1 -1
  48. package/dist/components/Tabs/TabsPanel.jsx +1 -1
  49. package/dist/components/Toast/ToastBox.jsx +1 -1
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +5 -0
  53. package/dist/utils/browser.d.ts +3 -0
  54. package/dist/utils/browser.d.ts.map +1 -0
  55. package/dist/utils/browser.js +21 -0
  56. package/dist/utils/cn.d.ts +3 -0
  57. package/dist/utils/cn.d.ts.map +1 -0
  58. package/dist/utils/cn.js +3 -0
  59. package/dist/utils/form.d.ts +2 -0
  60. package/dist/utils/form.d.ts.map +1 -0
  61. package/dist/utils/form.js +8 -0
  62. package/package.json +4 -3
  63. package/src/components/AccessNavigation/AccessNavigation.tsx +0 -46
  64. package/src/components/Accordion/Accordion.ts +0 -8
  65. package/src/components/Accordion/AccordionBody.tsx +0 -31
  66. package/src/components/Accordion/AccordionContext.ts +0 -8
  67. package/src/components/Accordion/AccordionRoot.tsx +0 -17
  68. package/src/components/Accordion/AccordionToggle.tsx +0 -29
  69. package/src/components/Affix/Affix.tsx +0 -59
  70. package/src/components/Breadcrumbs/Breadcrumbs.ts +0 -6
  71. package/src/components/Breadcrumbs/BreadcrumbsContext.ts +0 -7
  72. package/src/components/Breadcrumbs/BreadcrumbsItem.tsx +0 -24
  73. package/src/components/Breadcrumbs/BreadcrumbsRoot.tsx +0 -21
  74. package/src/components/Carousel/Carousel.ts +0 -6
  75. package/src/components/Carousel/CarouselContainer.tsx +0 -18
  76. package/src/components/Carousel/CarouselContext.ts +0 -7
  77. package/src/components/Carousel/CarouselRoot.tsx +0 -75
  78. package/src/components/ClientOnly/ClientOnly.tsx +0 -12
  79. package/src/components/Clipboard/Clipboard.tsx +0 -36
  80. package/src/components/ContextMenu/ContextMenu.ts +0 -6
  81. package/src/components/ContextMenu/ContextMenuContent.tsx +0 -51
  82. package/src/components/ContextMenu/ContextMenuContext.ts +0 -9
  83. package/src/components/ContextMenu/ContextMenuRoot.tsx +0 -79
  84. package/src/components/Drawer/Drawer.ts +0 -10
  85. package/src/components/Drawer/DrawerBody.tsx +0 -67
  86. package/src/components/Drawer/DrawerContext.ts +0 -8
  87. package/src/components/Drawer/DrawerPortal.tsx +0 -40
  88. package/src/components/Drawer/DrawerRoot.tsx +0 -45
  89. package/src/components/Drawer/DrawerToggle.tsx +0 -21
  90. package/src/components/Dropdown/Dropdown.ts +0 -8
  91. package/src/components/Dropdown/DropdownContext.ts +0 -10
  92. package/src/components/Dropdown/DropdownMenu.tsx +0 -34
  93. package/src/components/Dropdown/DropdownRoot.tsx +0 -90
  94. package/src/components/Dropdown/DropdownToggle.tsx +0 -23
  95. package/src/components/LinkLoader/LinkLoader.tsx +0 -16
  96. package/src/components/Modal/Modal.ts +0 -14
  97. package/src/components/Modal/ModalBody.tsx +0 -12
  98. package/src/components/Modal/ModalContent.tsx +0 -44
  99. package/src/components/Modal/ModalContext.ts +0 -8
  100. package/src/components/Modal/ModalHeader.tsx +0 -10
  101. package/src/components/Modal/ModalPortal.tsx +0 -40
  102. package/src/components/Modal/ModalRoot.tsx +0 -47
  103. package/src/components/Modal/ModalTrigger.tsx +0 -21
  104. package/src/components/Otp/Otp.ts +0 -8
  105. package/src/components/Otp/OtpContext.ts +0 -10
  106. package/src/components/Otp/OtpHiddenInput.tsx +0 -15
  107. package/src/components/Otp/OtpInputs.tsx +0 -86
  108. package/src/components/Otp/OtpRoot.tsx +0 -26
  109. package/src/components/Pagination/Pagination.ts +0 -15
  110. package/src/components/Pagination/PaginationContext.tsx +0 -10
  111. package/src/components/Pagination/PaginationCounts.tsx +0 -17
  112. package/src/components/Pagination/PaginationNextBtn.tsx +0 -27
  113. package/src/components/Pagination/PaginationPrevBtn.tsx +0 -27
  114. package/src/components/Pagination/PaginationSearchParamsRoot.tsx +0 -45
  115. package/src/components/Pagination/PaginationStateRoot.tsx +0 -23
  116. package/src/components/PasswordInput/PasswordInput.ts +0 -8
  117. package/src/components/PasswordInput/PasswordInputContext.tsx +0 -8
  118. package/src/components/PasswordInput/PasswordInputField.tsx +0 -15
  119. package/src/components/PasswordInput/PasswordInputRoot.tsx +0 -17
  120. package/src/components/PasswordInput/PasswordInputToggle.tsx +0 -52
  121. package/src/components/Portal/Portal.tsx +0 -17
  122. package/src/components/Progress/Progress.ts +0 -6
  123. package/src/components/Progress/ProgressBar.tsx +0 -29
  124. package/src/components/Progress/ProgressContext.ts +0 -8
  125. package/src/components/Progress/ProgressRoot.tsx +0 -22
  126. package/src/components/QrCode/QrCode.tsx +0 -22
  127. package/src/components/Rating/Rating.ts +0 -6
  128. package/src/components/Rating/RatingContext.ts +0 -8
  129. package/src/components/Rating/RatingItems.tsx +0 -50
  130. package/src/components/Rating/RatingRoot.tsx +0 -22
  131. package/src/components/Sheet/Sheet.tsx +0 -14
  132. package/src/components/Sheet/SheetBody.tsx +0 -49
  133. package/src/components/Sheet/SheetContent.tsx +0 -8
  134. package/src/components/Sheet/SheetContext.ts +0 -14
  135. package/src/components/Sheet/SheetHeader.tsx +0 -24
  136. package/src/components/Sheet/SheetPortal.tsx +0 -35
  137. package/src/components/Sheet/SheetRoot.tsx +0 -56
  138. package/src/components/Sheet/SheetToggle.tsx +0 -21
  139. package/src/components/ShowMore/ShowMore.ts +0 -10
  140. package/src/components/ShowMore/ShowMoreContent.tsx +0 -31
  141. package/src/components/ShowMore/ShowMoreContext.ts +0 -11
  142. package/src/components/ShowMore/ShowMoreFade.tsx +0 -18
  143. package/src/components/ShowMore/ShowMoreRoot.tsx +0 -37
  144. package/src/components/ShowMore/ShowMoreTrigger.tsx +0 -23
  145. package/src/components/Slide/Slide.ts +0 -12
  146. package/src/components/Slide/SlideContent.tsx +0 -8
  147. package/src/components/Slide/SlideContext.ts +0 -11
  148. package/src/components/Slide/SlideHeader.tsx +0 -10
  149. package/src/components/Slide/SlidePortal.tsx +0 -26
  150. package/src/components/Slide/SlideRoot.tsx +0 -39
  151. package/src/components/Slide/SlideToggle.tsx +0 -21
  152. package/src/components/Spoiler/Spoiler.tsx +0 -28
  153. package/src/components/Steps/Steps.ts +0 -15
  154. package/src/components/Steps/StepsContext.tsx +0 -16
  155. package/src/components/Steps/StepsControls.tsx +0 -56
  156. package/src/components/Steps/StepsNextBtn.tsx +0 -27
  157. package/src/components/Steps/StepsPrevBtn.tsx +0 -27
  158. package/src/components/Steps/StepsSearchParamsRoot.tsx +0 -45
  159. package/src/components/Steps/StepsStateRoot.tsx +0 -23
  160. package/src/components/Swap/Swap.ts +0 -8
  161. package/src/components/Swap/SwapContext.ts +0 -9
  162. package/src/components/Swap/SwapItem.tsx +0 -16
  163. package/src/components/Swap/SwapRoot.tsx +0 -29
  164. package/src/components/Swap/SwapTrigger.tsx +0 -31
  165. package/src/components/Tabs/Tabs.ts +0 -10
  166. package/src/components/Tabs/TabsContext.ts +0 -11
  167. package/src/components/Tabs/TabsList.tsx +0 -12
  168. package/src/components/Tabs/TabsPanel.tsx +0 -23
  169. package/src/components/Tabs/TabsRoot.tsx +0 -18
  170. package/src/components/Tabs/TabsTab.tsx +0 -23
  171. package/src/components/Toast/Toast.ts +0 -3
  172. package/src/components/Toast/ToastBox.tsx +0 -50
  173. package/src/components/Toast/ToastRoot.tsx +0 -71
  174. package/src/components/Toast/toastStore.ts +0 -22
  175. package/src/components/Toggle/Toggle.ts +0 -6
  176. package/src/components/Toggle/ToggleContext.ts +0 -9
  177. package/src/components/Toggle/ToggleRoot.tsx +0 -26
  178. package/src/components/Toggle/ToggleSwitch.tsx +0 -41
  179. package/src/index.ts +0 -28
@@ -1,17 +0,0 @@
1
- "use client";
2
-
3
- import { PropsWithChildren, useState } from "react";
4
-
5
- import { AccordionContext } from "./AccordionContext";
6
-
7
- export type AccordionRootPropsT = PropsWithChildren;
8
-
9
- export function AccordionRoot({ children }: AccordionRootPropsT) {
10
- const [isOpen, setOpen] = useState(false);
11
-
12
- return (
13
- <AccordionContext value={{ isOpen, setOpen }}>
14
- {children}
15
- </AccordionContext>
16
- )
17
- }
@@ -1,29 +0,0 @@
1
- "use client";
2
-
3
- import { ChevronRightIcon } from "lucide-react";
4
- import { HTMLAttributes, ReactNode, use } from "react";
5
-
6
- import { AccordionContext } from "./AccordionContext";
7
-
8
- export type AccordionTogglePropsT = HTMLAttributes<HTMLButtonElement> & {
9
- icon?: ReactNode;
10
- }
11
-
12
- export function AccordionToggle({ icon, children, onClick, ...props }: AccordionTogglePropsT) {
13
- const { isOpen, setOpen } = use(AccordionContext);
14
-
15
- return (
16
- <button
17
- onClick={ev => {
18
- onClick?.(ev)
19
- setOpen(prev => !prev)
20
- }}
21
- {...props}
22
- >
23
- <span className={`transition-transform ${isOpen ? "rotate-90" : ""}`}>
24
- {icon || <ChevronRightIcon className="compatible-icon" />}
25
- </span>
26
- {children}
27
- </button>
28
- )
29
- }
@@ -1,59 +0,0 @@
1
- "use client";
2
-
3
- import { cn } from "@kadoui/utils";
4
- import { ChevronUpIcon } from "lucide-react";
5
- import { useState, useEffect, HTMLAttributes } from "react";
6
-
7
- export type AffixPropsT = HTMLAttributes<HTMLButtonElement>
8
-
9
- export const Affix = ({ className, onClick, "aria-label": ariaLabel, children, ...props }: AffixPropsT) => {
10
- const [isVisible, setIsVisible] = useState(false);
11
- const [lastScrollY, setLastScrollY] = useState(0);
12
-
13
- useEffect(() => {
14
- const handleScroll = () => {
15
- const currentScrollY = window.scrollY;
16
- const viewportHeight = window.innerHeight;
17
- const scrollThreshold = viewportHeight * 0.5;
18
-
19
- if (currentScrollY > scrollThreshold && currentScrollY > lastScrollY) {
20
- setIsVisible(true);
21
- } else if (currentScrollY < lastScrollY && currentScrollY < scrollThreshold) {
22
- setIsVisible(false);
23
- }
24
-
25
- setLastScrollY(currentScrollY);
26
- };
27
-
28
- window.addEventListener("scroll", handleScroll, {
29
- passive: true
30
- });
31
-
32
- return () => window.removeEventListener("scroll", handleScroll);
33
- }, [lastScrollY]);
34
-
35
- const scrollToTop = () => {
36
- window.scrollTo({
37
- top: 0,
38
- behavior: "smooth"
39
- });
40
- };
41
-
42
- return (
43
- <button
44
- onClick={ev => {
45
- onClick?.(ev)
46
- scrollToTop()
47
- }}
48
- aria-label={ariaLabel || "Scroll to top"}
49
- className={cn(
50
- "fixed bottom-3 right-4 transition-all z-50",
51
- isVisible ? "" : "opacity-0 translate-y-3 pointer-events-none",
52
- className
53
- )}
54
- {...props}
55
- >
56
- {children || <ChevronUpIcon className="compatible-icon" />}
57
- </button>
58
- );
59
- }
@@ -1,6 +0,0 @@
1
- import { BreadcrumbsItem } from "./BreadcrumbsItem";
2
- import { BreadcrumbsRoot } from "./BreadcrumbsRoot";
3
-
4
- export const Breadcrumbs = Object.assign(BreadcrumbsRoot, {
5
- Item: BreadcrumbsItem,
6
- });
@@ -1,7 +0,0 @@
1
- import { createContext, ReactNode } from "react";
2
-
3
- export type BreadcrumbsContextT = {
4
- separator: ReactNode;
5
- }
6
-
7
- export const BreadcrumbsContext = createContext<BreadcrumbsContextT>({} as BreadcrumbsContextT);
@@ -1,24 +0,0 @@
1
- "use client"
2
-
3
- import { cn } from "@kadoui/utils";
4
- import { type HTMLAttributes, use } from "react";
5
-
6
- import { BreadcrumbsContext } from "./BreadcrumbsContext";
7
-
8
- export type BreadcrumbsItemPropsT = HTMLAttributes<HTMLDivElement> & {
9
- isLast?: boolean;
10
- }
11
-
12
- export function BreadcrumbsItem({ isLast = false, className, children, ...p }: BreadcrumbsItemPropsT) {
13
- const { separator } = use(BreadcrumbsContext);
14
-
15
- return (
16
- <div
17
- className={cn("f-center gap-1.5", className)}
18
- {...p}
19
- >
20
- {children}
21
- {!isLast && separator}
22
- </div>
23
- )
24
- }
@@ -1,21 +0,0 @@
1
- "use client"
2
-
3
- import { cn } from "@kadoui/utils";
4
- import type { HTMLAttributes, ReactNode } from "react";
5
-
6
- import { BreadcrumbsContext } from "./BreadcrumbsContext";
7
-
8
- export type BreadcrumbsRootPropsT = HTMLAttributes<HTMLElement> & {
9
- separator?: ReactNode;
10
- }
11
-
12
- export function BreadcrumbsRoot({ separator = "/", className, ...p }: BreadcrumbsRootPropsT) {
13
- return (
14
- <BreadcrumbsContext value={{ separator }}>
15
- <nav
16
- className={cn("f-align gap-3", className)}
17
- {...p}
18
- />
19
- </BreadcrumbsContext>
20
- )
21
- }
@@ -1,6 +0,0 @@
1
- import { CarouselRoot } from "./CarouselRoot";
2
- import { CarouselContainer } from "./CarouselContainer";
3
-
4
- export const Carousel = Object.assign(CarouselRoot, {
5
- Container: CarouselContainer
6
- });
@@ -1,18 +0,0 @@
1
- "use client";
2
-
3
- import { cn } from "@kadoui/utils";
4
- import { HTMLAttributes, use } from "react";
5
-
6
- import { CarouselContext } from "./CarouselContext";
7
-
8
- export type CarouselContainerPropsT = HTMLAttributes<HTMLDivElement>;
9
-
10
- export function CarouselContainer({ children, className, ...p }: CarouselContainerPropsT) {
11
- const { scrollRef } = use(CarouselContext);
12
-
13
- return (
14
- <div ref={scrollRef} className={cn("f-align-scroll", className)} {...p}>
15
- {children}
16
- </div>
17
- );
18
- }
@@ -1,7 +0,0 @@
1
- import { createContext, RefObject } from "react";
2
-
3
- export type CarouselContextPropsT = {
4
- scrollRef: RefObject<HTMLDivElement | null>;
5
- }
6
-
7
- export const CarouselContext = createContext<CarouselContextPropsT>({} as CarouselContextPropsT);
@@ -1,75 +0,0 @@
1
- "use client";
2
-
3
- import { cn } from "@kadoui/utils";
4
- import { HTMLAttributes, useEffect, useRef, useState } from "react";
5
-
6
- import { CarouselContext } from "./CarouselContext";
7
-
8
- export type CarouselRootPropsT = HTMLAttributes<HTMLDivElement>;
9
-
10
- export function CarouselRoot({ children, className, ...props }: CarouselRootPropsT) {
11
- const scrollRef = useRef<HTMLDivElement>(null);
12
- const [leftOpacity, setLeftOpacity] = useState(0);
13
- const [rightOpacity, setRightOpacity] = useState(1);
14
-
15
- const updateFade = () => {
16
- const el = scrollRef.current;
17
- if (!el) return;
18
-
19
- const { scrollLeft, scrollWidth, clientWidth } = el;
20
- const maxScroll = scrollWidth - clientWidth;
21
-
22
- if (maxScroll <= 0) {
23
- setLeftOpacity(0);
24
- setRightOpacity(0);
25
- return;
26
- }
27
-
28
- const scrollRatio = Math.abs(+(scrollLeft / maxScroll));
29
-
30
- const left = Math.min(1, scrollRatio * 2);
31
- const right = Math.min(1, (1 - scrollRatio) * 2);
32
-
33
- setLeftOpacity(+left.toFixed(1));
34
- setRightOpacity(+right.toFixed(1));
35
- };
36
-
37
- useEffect(() => {
38
- const el = scrollRef.current;
39
- if (!el) return;
40
-
41
- updateFade();
42
-
43
- el.addEventListener("scroll", updateFade);
44
- window.addEventListener("resize", updateFade);
45
-
46
- return () => {
47
- el.removeEventListener("scroll", updateFade);
48
- window.removeEventListener("resize", updateFade);
49
- };
50
- }, []);
51
-
52
- return (
53
- <CarouselContext value={{ scrollRef }}>
54
- <div className={cn("relative", className)} {...props}>
55
- {/* Left Fade */}
56
- <div
57
- className="pointer-events-none absolute right-0 top-0 h-full w-1/6 bg-gradient-to-l from-background from-5% to-transparent z-10 transition-opacity"
58
- style={{ opacity: leftOpacity }}
59
- />
60
- {/* --- */}
61
-
62
- {/* Scrollable container */}
63
- {children}
64
- {/* --- */}
65
-
66
- {/* Right Fade */}
67
- <div
68
- className="pointer-events-none absolute left-0 top-0 h-full w-1/6 bg-gradient-to-r from-background from-5% to-transparent z-10 transition-opacity"
69
- style={{ opacity: rightOpacity }}
70
- />
71
- {/* --- */}
72
- </div>
73
- </CarouselContext>
74
- );
75
- }
@@ -1,12 +0,0 @@
1
- "use client";
2
-
3
- import { PropsWithChildren } from "react";
4
- import { useMounted } from "@mantine/hooks";
5
-
6
- export type ClientOnlyPropsT = PropsWithChildren;
7
-
8
- export function ClientOnly({ children }: ClientOnlyPropsT) {
9
- const mounted = useMounted();
10
-
11
- return mounted ? children : null;
12
- }
@@ -1,36 +0,0 @@
1
- "use client";
2
-
3
- import { CopyCheckIcon, CopyIcon } from "lucide-react";
4
- import { ButtonHTMLAttributes, MouseEvent } from "react";
5
-
6
- import { useClipboard } from "@mantine/hooks";
7
-
8
- export type ClipboardPropsT = ButtonHTMLAttributes<HTMLButtonElement> & {
9
- text: string;
10
- timeout?: number;
11
- }
12
-
13
- export function Clipboard({ onClick, children, text, timeout = 3_000, ...props }: ClipboardPropsT) {
14
- const { copy, copied } = useClipboard({ timeout });
15
-
16
- const handleClick = (ev: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) => {
17
- onClick?.(ev);
18
- copy(text.trim());
19
- };
20
-
21
- return (
22
- <button
23
- aria-label={text}
24
- onClick={handleClick}
25
- {...props}
26
- >
27
- {copied ? (
28
- <CopyCheckIcon className="compatible-icon" />
29
- ) : (
30
- <CopyIcon className="compatible-icon" />
31
- )}
32
-
33
- {children}
34
- </button>
35
- );
36
- }
@@ -1,6 +0,0 @@
1
- import { ContextMenuRoot } from "./ContextMenuRoot";
2
- import { ContextMenuContent } from "./ContextMenuContent";
3
-
4
- export const ContextMenu = Object.assign(ContextMenuRoot, {
5
- Content: ContextMenuContent
6
- });
@@ -1,51 +0,0 @@
1
- "use client";
2
-
3
- import { HTMLAttributes, use, useEffect } from "react";
4
- import { cn, selectAccessibleChildren } from "@kadoui/utils";
5
-
6
- import { ContextMenuContext } from "./ContextMenuContext";
7
-
8
- export type ContextMenuContentPropsT = HTMLAttributes<HTMLDivElement>;
9
-
10
- export function ContextMenuContent({ onContextMenu, className, ...p }: ContextMenuContentPropsT) {
11
- const { contentRef, position, isOpen } = use(ContextMenuContext);
12
-
13
- useEffect(() => {
14
- if (!contentRef.current) {
15
- return;
16
- }
17
-
18
- if (isOpen) {
19
- const children = selectAccessibleChildren(contentRef.current);
20
- const firstChild = children[0];
21
-
22
- if (!firstChild) {
23
- return;
24
- }
25
-
26
- firstChild.focus();
27
- }
28
- }, [isOpen, position, contentRef])
29
-
30
- return (
31
- <div
32
- ref={contentRef}
33
- onContextMenu={ev => {
34
- ev.stopPropagation();
35
- ev.preventDefault();
36
- onContextMenu?.(ev);
37
- }}
38
- className={cn(
39
- "z-50 fixed",
40
- position ? "transition-all" : "",
41
- isOpen ? "" : "hidden",
42
- className
43
- )}
44
- style={{
45
- top: position?.y,
46
- left: position?.x,
47
- }}
48
- {...p}
49
- />
50
- )
51
- }
@@ -1,9 +0,0 @@
1
- import { createContext, RefObject } from 'react'
2
-
3
- export type ContextMenuContextT = {
4
- isOpen: boolean;
5
- position: { x: number, y: number } | undefined;
6
- contentRef: RefObject<HTMLDivElement | null>;
7
- }
8
-
9
- export const ContextMenuContext = createContext<ContextMenuContextT>({} as ContextMenuContextT);
@@ -1,79 +0,0 @@
1
- "use client";
2
-
3
- import { getBrowserScrollbarWith } from "@kadoui/utils";
4
- import { HTMLAttributes, MouseEvent, useCallback, useEffect, useRef, useState } from "react";
5
-
6
- import { ContextMenuContext, ContextMenuContextT } from "./ContextMenuContext";
7
-
8
- export type ContextMenuRootPropsT = HTMLAttributes<HTMLDivElement>;
9
-
10
- export function ContextMenuRoot({ onContextMenu, ...p }: ContextMenuRootPropsT) {
11
- const [position, setPosition] = useState<ContextMenuContextT["position"]>(undefined);
12
- const [isOpen, setOpen] = useState(false);
13
-
14
- const contentRef = useRef<HTMLDivElement>(null);
15
-
16
- const handleClickOutside = useCallback((ev: globalThis.MouseEvent) => {
17
- if (!contentRef.current?.contains(ev.target as Node)) {
18
- setOpen(false);
19
- setPosition(undefined);
20
- }
21
- }, []);
22
-
23
- useEffect(() => {
24
- document.addEventListener("click", handleClickOutside);
25
-
26
- return () => document.removeEventListener("click", handleClickOutside);
27
- }, [handleClickOutside]);
28
-
29
- useEffect(() => {
30
- const scrollbarWidth = getBrowserScrollbarWith();
31
-
32
- if (isOpen) {
33
- document.body.style.overflow = "hidden";
34
- document.body.style.paddingRight = `${scrollbarWidth}px`;
35
- } else {
36
- document.body.style.overflow = "unset";
37
- document.body.style.paddingRight = "0px";
38
- };
39
- }, [isOpen]);
40
-
41
-
42
- const handleContextMenu = (ev: MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
43
- if (!contentRef.current) return;
44
-
45
- ev.preventDefault();
46
-
47
- const viewportWidth = window.innerWidth;
48
- const viewportHeight = window.innerHeight;
49
-
50
- const menuWidth = contentRef.current.scrollWidth;
51
- const menuHeight = contentRef.current.scrollHeight;
52
-
53
- let x = ev.clientX;
54
- let y = ev.clientY;
55
-
56
- if (x + menuWidth > viewportWidth) {
57
- x = viewportWidth - menuWidth - 10;
58
- }
59
- if (y + menuHeight > viewportHeight) {
60
- y = viewportHeight - menuHeight - 10;
61
- }
62
-
63
- setPosition({ x, y });
64
- setOpen(true);
65
- }
66
-
67
-
68
- return (
69
- <ContextMenuContext value={{ contentRef, isOpen, position }}>
70
- <div
71
- onContextMenu={ev => {
72
- onContextMenu?.(ev);
73
- handleContextMenu(ev);
74
- }}
75
- {...p}
76
- />
77
- </ContextMenuContext>
78
- )
79
- }
@@ -1,10 +0,0 @@
1
- import { DrawerBody } from "./DrawerBody";
2
- import { DrawerRoot } from "./DrawerRoot";
3
- import { DrawerPortal } from "./DrawerPortal";
4
- import { DrawerToggle } from "./DrawerToggle";
5
-
6
- export const Drawer = Object.assign(DrawerRoot, {
7
- Toggle: DrawerToggle,
8
- Portal: DrawerPortal,
9
- Body: DrawerBody
10
- });
@@ -1,67 +0,0 @@
1
- "use client";
2
-
3
- import { cn } from "@kadoui/utils";
4
- import { motion, HTMLMotionProps } from "framer-motion";
5
- import { ReactNode, use, useEffect, useRef } from "react";
6
-
7
- import { DrawerContext } from "./DrawerContext";
8
-
9
- export type DrawerBodyPropsT = HTMLMotionProps<"div"> & {
10
- position?: "top" | "right" | "bottom" | "left";
11
- };
12
-
13
- export function DrawerBody({ position, dir, children, className, ...props }: DrawerBodyPropsT) {
14
- const { isOpen } = use(DrawerContext);
15
-
16
- const bodyRef = useRef<HTMLDivElement>(null);
17
-
18
- useEffect(() => {
19
- if (isOpen) {
20
- const indexElement = bodyRef.current?.querySelector("[data-drawer='index']") as HTMLElement | null | undefined;
21
- indexElement?.focus();
22
- };
23
- }, [isOpen]);
24
-
25
- const currentDir: "ltr" | "rtl" = (dir || document.documentElement.getAttribute("dir") || "ltr") as ("ltr" | "rtl");
26
- const currentPosition = position || (currentDir === "ltr" ? "left" : "right");
27
- const direction = ["right", "left"].includes(currentPosition) ? "y" : "x";
28
-
29
- const width = direction === "y" ? "clamp(300px,30%,30%)" : undefined;
30
- const height = direction === "y" ? undefined : "50%";
31
-
32
- return (
33
- <motion.div
34
- ref={bodyRef}
35
- onClick={ev => ev.stopPropagation()}
36
- className={cn("absolute bg-background p-3 overflow-y-auto", className)}
37
- initial={
38
- direction === "y"
39
- ? { x: currentPosition === "left" ? "-100%" : "100%" }
40
- : { y: currentPosition === "top" ? "-100%" : "100%" }
41
- }
42
- animate={{ y: 0, x: 0 }}
43
- exit={
44
- direction === "y"
45
- ? { x: currentPosition === "left" ? "-100%" : "100%" }
46
- : { y: currentPosition === "top" ? "-100%" : "100%" }
47
- }
48
- style={{
49
- width,
50
- height,
51
- ...(
52
- currentPosition === "top"
53
- ? { top: 0, left: 0, right: 0 }
54
- : currentPosition === "right"
55
- ? { top: 0, bottom: 0, right: 0 }
56
- : currentPosition === "bottom"
57
- ? { bottom: 0, left: 0, right: 0 }
58
- : { top: 0, bottom: 0, left: 0 }
59
- )
60
- }}
61
- transition={{ ease: "easeInOut" }}
62
- {...props}
63
- >
64
- {children as ReactNode}
65
- </motion.div>
66
- );
67
- };
@@ -1,8 +0,0 @@
1
- import { createContext, Dispatch, SetStateAction } from "react";
2
-
3
- export type DrawerContextT = {
4
- isOpen: boolean;
5
- setOpen: Dispatch<SetStateAction<boolean>>;
6
- };
7
-
8
- export const DrawerContext = createContext<DrawerContextT>({} as DrawerContextT);
@@ -1,40 +0,0 @@
1
- "use client";
2
-
3
- import { use } from "react";
4
- import { cn } from "@kadoui/utils";
5
- import { motion, AnimatePresence, HTMLMotionProps } from "framer-motion";
6
-
7
- import { Portal } from "../Portal/Portal";
8
- import { DrawerContext } from "./DrawerContext";
9
- import { ClientOnly } from "../ClientOnly/ClientOnly";
10
-
11
- export type DrawerPortalPropsT = HTMLMotionProps<"div">;
12
-
13
- export function DrawerPortal({ onClick, className, ...props }: DrawerPortalPropsT) {
14
- const { isOpen, setOpen } = use(DrawerContext);
15
-
16
- return (
17
- <ClientOnly>
18
- <Portal>
19
- <AnimatePresence>
20
- {isOpen ? (
21
- <motion.div
22
- initial={{ opacity: 0 }}
23
- animate={{ opacity: 1 }}
24
- exit={{ opacity: 0 }}
25
- onClick={ev => {
26
- onClick?.(ev);
27
- setOpen(false);
28
- }}
29
- className={cn(
30
- "fixed inset-0 z-50 bg-foreground/50",
31
- className
32
- )}
33
- {...props}
34
- />
35
- ) : null}
36
- </AnimatePresence>
37
- </Portal>
38
- </ClientOnly>
39
- );
40
- }
@@ -1,45 +0,0 @@
1
- "use client"
2
-
3
- import { getBrowserScrollbarWith } from "@kadoui/utils";
4
- import { useState, useEffect, PropsWithChildren } from "react";
5
-
6
- import { DrawerContext } from "./DrawerContext";
7
-
8
- export type DrawerRootPropsT = PropsWithChildren;
9
-
10
- export function DrawerRoot({ children }: DrawerRootPropsT) {
11
- const [isOpen, setOpen] = useState(false);
12
-
13
- useEffect(() => {
14
- const handleEscape = (ev: KeyboardEvent) => {
15
- if (ev.key === "Escape") {
16
- setOpen(false);
17
- };
18
- };
19
-
20
- document.addEventListener("keydown", handleEscape);
21
-
22
- return () => {
23
- document.removeEventListener("keydown", handleEscape);
24
- document.body.style.overflow = "unset";
25
- };
26
- }, [])
27
-
28
- useEffect(() => {
29
- const scrollbarWidth = getBrowserScrollbarWith();
30
-
31
- if (isOpen) {
32
- document.body.style.overflow = "hidden";
33
- document.body.style.paddingRight = `${scrollbarWidth}px`;
34
- } else {
35
- document.body.style.overflow = "unset";
36
- document.body.style.paddingRight = "0px";
37
- };
38
- }, [isOpen]);
39
-
40
- return (
41
- <DrawerContext value={{ isOpen, setOpen }}>
42
- {children}
43
- </DrawerContext>
44
- );
45
- }
@@ -1,21 +0,0 @@
1
- "use client";
2
-
3
- import { ButtonHTMLAttributes, use } from "react";
4
-
5
- import { DrawerContext } from "./DrawerContext";
6
-
7
- export type DrawerTogglePropsT = ButtonHTMLAttributes<HTMLButtonElement>;
8
-
9
- export function DrawerToggle({ onClick, ...props }: DrawerTogglePropsT) {
10
- const { setOpen } = use(DrawerContext);
11
-
12
- return (
13
- <button
14
- onClick={(ev) => {
15
- onClick?.(ev);
16
- setOpen(prev => !prev);
17
- }}
18
- {...props}
19
- />
20
- );
21
- }