@intlayer/design-system 8.7.0-canary.0 → 8.7.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/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +3 -3
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
- package/dist/esm/components/Form/elements/FormElement.mjs +2 -1
- package/dist/esm/components/Form/elements/FormElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/FormElementWrapper.mjs.map +1 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
- package/dist/esm/components/Form/layout/FormItemLayout.mjs +3 -2
- package/dist/esm/components/Form/layout/FormItemLayout.mjs.map +1 -1
- package/dist/esm/components/IDE/MonacoCode.mjs +1 -0
- package/dist/esm/components/IDE/MonacoCode.mjs.map +1 -1
- package/dist/esm/components/Link/Link.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +2 -2
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +2 -2
- package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
- package/dist/esm/components/Navbar/index.mjs +2 -57
- package/dist/esm/components/Navbar/index.mjs.map +1 -1
- package/dist/esm/components/Pagination/Pagination.mjs +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
- package/dist/esm/components/Table/SmartTable.mjs +222 -0
- package/dist/esm/components/Table/SmartTable.mjs.map +1 -0
- package/dist/esm/components/Table/Table.mjs +7 -212
- package/dist/esm/components/Table/Table.mjs.map +1 -1
- package/dist/esm/components/Table/index.mjs +2 -1
- package/dist/esm/components/TextArea/ContentEditableTextArea.mjs +1 -1
- package/dist/esm/components/TextArea/ContentEditableTextArea.mjs.map +1 -1
- package/dist/esm/components/index.mjs +5 -1
- package/dist/esm/hooks/index.mjs +9 -9
- package/dist/esm/hooks/reactQuery.mjs +1 -3
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useOAuth2.mjs +1 -1
- package/dist/esm/hooks/useAuth/useSession.mjs +1 -1
- package/dist/esm/libs/auth.mjs +7 -3
- package/dist/esm/libs/auth.mjs.map +1 -1
- package/dist/esm/routes.mjs +1 -1
- package/dist/esm/routes.mjs.map +1 -1
- package/dist/types/components/Button/Button.d.ts +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +1 -1
- package/dist/types/components/Command/index.d.ts +1 -1
- package/dist/types/components/Container/index.d.ts +3 -3
- package/dist/types/components/Form/elements/FormElement.d.ts +1 -0
- package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
- package/dist/types/components/Form/layout/FormItemLayout.d.ts +1 -0
- package/dist/types/components/Form/layout/FormItemLayout.d.ts.map +1 -1
- package/dist/types/components/Input/Checkbox.d.ts +1 -1
- package/dist/types/components/Link/Link.d.ts +1 -1
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts +3 -3
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
- package/dist/types/components/Navbar/index.d.ts +4 -1
- package/dist/types/components/Navbar/index.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +1 -1
- package/dist/types/components/TabSelector/TabSelector.d.ts +1 -1
- package/dist/types/components/Table/SmartTable.d.ts +158 -0
- package/dist/types/components/Table/SmartTable.d.ts.map +1 -0
- package/dist/types/components/Table/Table.d.ts +8 -191
- package/dist/types/components/Table/Table.d.ts.map +1 -1
- package/dist/types/components/Table/index.d.ts +3 -2
- package/dist/types/components/TextArea/ContentEditableTextArea.d.ts +2 -2
- package/dist/types/components/TextArea/ContentEditableTextArea.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toast.d.ts +1 -1
- package/dist/types/components/index.d.ts +6 -2
- package/dist/types/hooks/reactQuery.d.ts.map +1 -1
- package/dist/types/routes.d.ts +1 -1
- package/dist/types/routes.d.ts.map +1 -1
- package/package.json +22 -22
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
5
|
-
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
6
4
|
import { Container } from "../Container/index.mjs";
|
|
7
5
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
8
6
|
import { H3 } from "../Headers/index.mjs";
|
|
7
|
+
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
8
|
+
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
9
9
|
import { useEffect } from "react";
|
|
10
10
|
import { cva } from "class-variance-authority";
|
|
11
11
|
import { X } from "lucide-react";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
+
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
4
5
|
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
5
6
|
import { useScrollDetection } from "../../hooks/useScrollDetection.mjs";
|
|
6
|
-
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
7
7
|
import { Burger } from "./Burger.mjs";
|
|
8
8
|
import { useRef, useState } from "react";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -3,66 +3,11 @@
|
|
|
3
3
|
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
4
4
|
import { useIsMounted } from "../../hooks/useIsMounted.mjs";
|
|
5
5
|
import { DesktopNavbar } from "./DesktopNavbar.mjs";
|
|
6
|
+
import { Burger } from "./Burger.mjs";
|
|
6
7
|
import { MobileNavbar } from "./MobileNavbar.mjs";
|
|
7
8
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
8
9
|
|
|
9
10
|
//#region src/components/Navbar/index.tsx
|
|
10
|
-
/**
|
|
11
|
-
* Responsive Navbar Component
|
|
12
|
-
*
|
|
13
|
-
* A highly adaptable navigation component that automatically switches between desktop and mobile
|
|
14
|
-
* layouts based on screen size. Provides comprehensive navigation structure with flexible content areas.
|
|
15
|
-
*
|
|
16
|
-
* Features:
|
|
17
|
-
* - Automatic responsive switching at 'lg' breakpoint (1024px)
|
|
18
|
-
* - Separate section configurations for desktop and mobile layouts
|
|
19
|
-
* - Support for logo placement and right-aligned utility items
|
|
20
|
-
* - Generic typing for tab properties and selected states
|
|
21
|
-
* - Mobile-specific top/bottom content areas for enhanced mobile UX
|
|
22
|
-
* - Hydration-safe rendering with useIsMounted hook
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* Basic usage:
|
|
26
|
-
* ```tsx
|
|
27
|
-
* const navSections = [
|
|
28
|
-
* { key: 'home', label: 'Home', href: '/' },
|
|
29
|
-
* { key: 'about', label: 'About', href: '/about' }
|
|
30
|
-
* ];
|
|
31
|
-
*
|
|
32
|
-
* <Navbar
|
|
33
|
-
* logo={<Logo />}
|
|
34
|
-
* selectedChoice="home"
|
|
35
|
-
* desktopSections={navSections}
|
|
36
|
-
* mobileTopSections={navSections}
|
|
37
|
-
* rightItemsDesktop={<UserMenu />}
|
|
38
|
-
* />
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* Advanced mobile configuration:
|
|
43
|
-
* ```tsx
|
|
44
|
-
* <Navbar
|
|
45
|
-
* logo={<Logo />}
|
|
46
|
-
* selectedChoice={activeTab}
|
|
47
|
-
* desktopSections={mainNavItems}
|
|
48
|
-
* mobileTopSections={primaryMobileNavItems}
|
|
49
|
-
* mobileTopChildren={<SearchBar />}
|
|
50
|
-
* mobileBottomSections={secondaryMobileNavItems}
|
|
51
|
-
* mobileBottomChildren={<UserProfile />}
|
|
52
|
-
* rightItemsDesktop={<DesktopActions />}
|
|
53
|
-
* rightItemsMobile={<MobileActions />}
|
|
54
|
-
* />
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* Responsive Behavior:
|
|
58
|
-
* - Desktop (≥1024px): Shows DesktopNavbar with horizontal layout
|
|
59
|
-
* - Mobile (<1024px): Shows MobileNavbar with collapsible vertical layout
|
|
60
|
-
* - Automatic detection with no flash of unstyled content
|
|
61
|
-
*
|
|
62
|
-
* @template T - Tab properties type extending TabProps for type safety
|
|
63
|
-
* @param props - Navbar component props
|
|
64
|
-
* @returns Responsive navbar JSX element
|
|
65
|
-
*/
|
|
66
11
|
const Navbar = ({ logo, mobileTopChildren, desktopSections = [], mobileTopSections = [], mobileBottomChildren, mobileBottomSections = [], rightItemsDesktop, rightItemsMobile, selectedChoice, mobileRollable = true }) => {
|
|
67
12
|
const { isMobile } = useDevice("lg");
|
|
68
13
|
if (!useIsMounted()) return /* @__PURE__ */ jsx(Fragment, {});
|
|
@@ -83,5 +28,5 @@ const Navbar = ({ logo, mobileTopChildren, desktopSections = [], mobileTopSectio
|
|
|
83
28
|
};
|
|
84
29
|
|
|
85
30
|
//#endregion
|
|
86
|
-
export { Navbar };
|
|
31
|
+
export { Burger, DesktopNavbar, MobileNavbar, Navbar };
|
|
87
32
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Navbar/index.tsx"],"sourcesContent":["'use client';\n\nimport { useDevice } from '@hooks/useDevice';\nimport { useIsMounted } from '@hooks/useIsMounted';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { TabSelectorItemProps } from '../TabSelector';\nimport { DesktopNavbar } from './DesktopNavbar';\nimport { MobileNavbar } from './MobileNavbar';\n\n/**\n * Props for the responsive Navbar component\n * @template T - The tab props type extending TabProps\n */\ntype NavbarProps<T extends TabSelectorItemProps> = {\n /** Logo component or element to display in navbar */\n logo: ReactNode;\n /** Currently selected tab key for active state management */\n selectedChoice: T['key'];\n /** Navigation sections displayed on desktop layout */\n desktopSections?: ReactElement<T>[];\n /** Additional content displayed at top of mobile navbar */\n mobileTopChildren?: ReactNode;\n /** Navigation sections displayed at top of mobile navbar */\n mobileTopSections?: ReactElement<T>[];\n /** Additional content displayed at bottom of mobile navbar */\n mobileBottomChildren?: ReactNode;\n /** Navigation sections displayed at bottom of mobile navbar */\n mobileBottomSections?: ReactElement<T>[];\n /** Right-aligned items for desktop navbar (e.g., user menu, settings) */\n rightItemsDesktop?: ReactNode;\n /** Right-aligned items for mobile navbar */\n rightItemsMobile?: ReactNode;\n /** Whether the mobile navbar should be rollable (default: true) */\n mobileRollable?: boolean;\n};\n\n/**\n * Responsive Navbar Component\n *\n * A highly adaptable navigation component that automatically switches between desktop and mobile\n * layouts based on screen size. Provides comprehensive navigation structure with flexible content areas.\n *\n * Features:\n * - Automatic responsive switching at 'lg' breakpoint (1024px)\n * - Separate section configurations for desktop and mobile layouts\n * - Support for logo placement and right-aligned utility items\n * - Generic typing for tab properties and selected states\n * - Mobile-specific top/bottom content areas for enhanced mobile UX\n * - Hydration-safe rendering with useIsMounted hook\n *\n * @example\n * Basic usage:\n * ```tsx\n * const navSections = [\n * { key: 'home', label: 'Home', href: '/' },\n * { key: 'about', label: 'About', href: '/about' }\n * ];\n *\n * <Navbar\n * logo={<Logo />}\n * selectedChoice=\"home\"\n * desktopSections={navSections}\n * mobileTopSections={navSections}\n * rightItemsDesktop={<UserMenu />}\n * />\n * ```\n *\n * @example\n * Advanced mobile configuration:\n * ```tsx\n * <Navbar\n * logo={<Logo />}\n * selectedChoice={activeTab}\n * desktopSections={mainNavItems}\n * mobileTopSections={primaryMobileNavItems}\n * mobileTopChildren={<SearchBar />}\n * mobileBottomSections={secondaryMobileNavItems}\n * mobileBottomChildren={<UserProfile />}\n * rightItemsDesktop={<DesktopActions />}\n * rightItemsMobile={<MobileActions />}\n * />\n * ```\n *\n * Responsive Behavior:\n * - Desktop (≥1024px): Shows DesktopNavbar with horizontal layout\n * - Mobile (<1024px): Shows MobileNavbar with collapsible vertical layout\n * - Automatic detection with no flash of unstyled content\n *\n * @template T - Tab properties type extending TabProps for type safety\n * @param props - Navbar component props\n * @returns Responsive navbar JSX element\n */\nexport const Navbar = <T extends TabSelectorItemProps>({\n logo,\n mobileTopChildren,\n desktopSections = [],\n mobileTopSections = [],\n mobileBottomChildren,\n mobileBottomSections = [],\n rightItemsDesktop,\n rightItemsMobile,\n selectedChoice,\n mobileRollable = true,\n}: NavbarProps<T>) => {\n const { isMobile } = useDevice('lg');\n const isMoUnted = useIsMounted();\n\n if (!isMoUnted) return <></>;\n\n return isMobile ? (\n <MobileNavbar\n topChildren={mobileTopChildren}\n topSections={mobileTopSections}\n bottomChildren={mobileBottomChildren}\n bottomSections={mobileBottomSections}\n logo={logo}\n rightItems={rightItemsMobile}\n rollable={mobileRollable}\n />\n ) : (\n <DesktopNavbar\n sections={desktopSections}\n rightItems={rightItemsDesktop}\n logo={logo}\n selectedChoice={selectedChoice}\n />\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Navbar/index.tsx"],"sourcesContent":["'use client';\n\nimport { useDevice } from '@hooks/useDevice';\nimport { useIsMounted } from '@hooks/useIsMounted';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { TabSelectorItemProps } from '../TabSelector';\nimport { DesktopNavbar } from './DesktopNavbar';\nimport { MobileNavbar } from './MobileNavbar';\n\n/**\n * Props for the responsive Navbar component\n * @template T - The tab props type extending TabProps\n */\ntype NavbarProps<T extends TabSelectorItemProps> = {\n /** Logo component or element to display in navbar */\n logo: ReactNode;\n /** Currently selected tab key for active state management */\n selectedChoice: T['key'];\n /** Navigation sections displayed on desktop layout */\n desktopSections?: ReactElement<T>[];\n /** Additional content displayed at top of mobile navbar */\n mobileTopChildren?: ReactNode;\n /** Navigation sections displayed at top of mobile navbar */\n mobileTopSections?: ReactElement<T>[];\n /** Additional content displayed at bottom of mobile navbar */\n mobileBottomChildren?: ReactNode;\n /** Navigation sections displayed at bottom of mobile navbar */\n mobileBottomSections?: ReactElement<T>[];\n /** Right-aligned items for desktop navbar (e.g., user menu, settings) */\n rightItemsDesktop?: ReactNode;\n /** Right-aligned items for mobile navbar */\n rightItemsMobile?: ReactNode;\n /** Whether the mobile navbar should be rollable (default: true) */\n mobileRollable?: boolean;\n};\n\n/**\n * Responsive Navbar Component\n *\n * A highly adaptable navigation component that automatically switches between desktop and mobile\n * layouts based on screen size. Provides comprehensive navigation structure with flexible content areas.\n *\n * Features:\n * - Automatic responsive switching at 'lg' breakpoint (1024px)\n * - Separate section configurations for desktop and mobile layouts\n * - Support for logo placement and right-aligned utility items\n * - Generic typing for tab properties and selected states\n * - Mobile-specific top/bottom content areas for enhanced mobile UX\n * - Hydration-safe rendering with useIsMounted hook\n *\n * @example\n * Basic usage:\n * ```tsx\n * const navSections = [\n * { key: 'home', label: 'Home', href: '/' },\n * { key: 'about', label: 'About', href: '/about' }\n * ];\n *\n * <Navbar\n * logo={<Logo />}\n * selectedChoice=\"home\"\n * desktopSections={navSections}\n * mobileTopSections={navSections}\n * rightItemsDesktop={<UserMenu />}\n * />\n * ```\n *\n * @example\n * Advanced mobile configuration:\n * ```tsx\n * <Navbar\n * logo={<Logo />}\n * selectedChoice={activeTab}\n * desktopSections={mainNavItems}\n * mobileTopSections={primaryMobileNavItems}\n * mobileTopChildren={<SearchBar />}\n * mobileBottomSections={secondaryMobileNavItems}\n * mobileBottomChildren={<UserProfile />}\n * rightItemsDesktop={<DesktopActions />}\n * rightItemsMobile={<MobileActions />}\n * />\n * ```\n *\n * Responsive Behavior:\n * - Desktop (≥1024px): Shows DesktopNavbar with horizontal layout\n * - Mobile (<1024px): Shows MobileNavbar with collapsible vertical layout\n * - Automatic detection with no flash of unstyled content\n *\n * @template T - Tab properties type extending TabProps for type safety\n * @param props - Navbar component props\n * @returns Responsive navbar JSX element\n */\nexport { Burger } from './Burger';\nexport { DesktopNavbar } from './DesktopNavbar';\nexport { MobileNavbar } from './MobileNavbar';\n\nexport const Navbar = <T extends TabSelectorItemProps>({\n logo,\n mobileTopChildren,\n desktopSections = [],\n mobileTopSections = [],\n mobileBottomChildren,\n mobileBottomSections = [],\n rightItemsDesktop,\n rightItemsMobile,\n selectedChoice,\n mobileRollable = true,\n}: NavbarProps<T>) => {\n const { isMobile } = useDevice('lg');\n const isMoUnted = useIsMounted();\n\n if (!isMoUnted) return <></>;\n\n return isMobile ? (\n <MobileNavbar\n topChildren={mobileTopChildren}\n topSections={mobileTopSections}\n bottomChildren={mobileBottomChildren}\n bottomSections={mobileBottomSections}\n logo={logo}\n rightItems={rightItemsMobile}\n rollable={mobileRollable}\n />\n ) : (\n <DesktopNavbar\n sections={desktopSections}\n rightItems={rightItemsDesktop}\n logo={logo}\n selectedChoice={selectedChoice}\n />\n );\n};\n"],"mappings":";;;;;;;;;;AAgGA,MAAa,UAA0C,EACrD,MACA,mBACA,kBAAkB,EAAE,EACpB,oBAAoB,EAAE,EACtB,sBACA,uBAAuB,EAAE,EACzB,mBACA,kBACA,gBACA,iBAAiB,WACG;CACpB,MAAM,EAAE,aAAa,UAAU,KAAK;AAGpC,KAAI,CAFc,cAAc,CAEhB,QAAO,gCAAK;AAE5B,QAAO,WACL,oBAAC,cAAD;EACE,aAAa;EACb,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EACV;EACN,YAAY;EACZ,UAAU;EACV,IAEF,oBAAC,eAAD;EACE,UAAU;EACV,YAAY;EACN;EACU;EAChB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
5
4
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
|
+
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
6
6
|
import { useEffect, useRef } from "react";
|
|
7
7
|
import { cva } from "class-variance-authority";
|
|
8
8
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
4
|
-
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
5
|
-
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
6
3
|
import { Container } from "../Container/index.mjs";
|
|
7
4
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
|
+
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
8
6
|
import { KeyboardShortcut } from "../KeyboardShortcut/KeyboardShortcut.mjs";
|
|
9
7
|
import { Popover } from "../Popover/dynamic.mjs";
|
|
8
|
+
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
9
|
+
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
10
10
|
import { MaxWidthSmoother } from "../MaxWidthSmoother/index.mjs";
|
|
11
11
|
import { isElementAtTopAndNotCovered } from "./isElementAtTopAndNotCovered.mjs";
|
|
12
12
|
import { useRightDrawer } from "./useRightDrawer.mjs";
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn.mjs";
|
|
4
|
+
import { ExpandCollapse } from "../ExpandCollapse/ExpandCollapse.mjs";
|
|
5
|
+
import { Modal, ModalSize } from "../Modal/Modal.mjs";
|
|
6
|
+
import { ExpandButton } from "./ExpandButton.mjs";
|
|
7
|
+
import { Table } from "./Table.mjs";
|
|
8
|
+
import { useTableWidths } from "./useTableWidths.mjs";
|
|
9
|
+
import { useEffect, useRef, useState } from "react";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
|
|
12
|
+
//#region src/components/Table/SmartTable.tsx
|
|
13
|
+
/**
|
|
14
|
+
* Table component that provides an enhanced table experience with modal expansion and collapsible content
|
|
15
|
+
*
|
|
16
|
+
* The Table component wraps a standard HTML table element with additional functionality:
|
|
17
|
+
* - **Modal Expansion**: Click the diagonal arrow button to view the table in a full-screen modal
|
|
18
|
+
* - **Collapsible Content**: Optionally wrap content in an ExpandCollapse component for space-saving
|
|
19
|
+
* - **Responsive Design**: Handles large tables gracefully with modal overflow
|
|
20
|
+
* - **Sticky Controls**: Table controls remain accessible even when scrolling
|
|
21
|
+
*
|
|
22
|
+
* ## Features
|
|
23
|
+
* - **Modal View**: Full-screen modal for better viewing of large tables
|
|
24
|
+
* - **Expand/Collapse**: Optional collapsible wrapper to save space
|
|
25
|
+
* - **Responsive**: Handles overflow and responsive behavior automatically
|
|
26
|
+
* - **Accessibility**: Maintains proper table semantics and keyboard navigation
|
|
27
|
+
* - **Customizable**: Supports all standard HTML table attributes and styling
|
|
28
|
+
*
|
|
29
|
+
* ## Best Practices
|
|
30
|
+
* - Use semantic HTML table structure (thead, tbody, tfoot)
|
|
31
|
+
* - Provide proper column headers with scope attributes
|
|
32
|
+
* - Use the isRollable prop for large tables that might need space management
|
|
33
|
+
* - Apply consistent styling through the className prop
|
|
34
|
+
* - Consider pagination for very large datasets
|
|
35
|
+
*
|
|
36
|
+
* @param {SmartTableProps} props - The properties for the Table component
|
|
37
|
+
* @returns {JSX.Element} The rendered table with enhanced functionality
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* // Simple data table
|
|
42
|
+
* <SmartTable>
|
|
43
|
+
* <thead>
|
|
44
|
+
* <tr>
|
|
45
|
+
* <th scope="col">Name</th>
|
|
46
|
+
* <th scope="col">Email</th>
|
|
47
|
+
* <th scope="col">Status</th>
|
|
48
|
+
* </tr>
|
|
49
|
+
* </thead>
|
|
50
|
+
* <tbody>
|
|
51
|
+
* <tr>
|
|
52
|
+
* <td>John Doe</td>
|
|
53
|
+
* <td>john@example.com</td>
|
|
54
|
+
* <td>
|
|
55
|
+
* <span className="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">
|
|
56
|
+
* Active
|
|
57
|
+
* </span>
|
|
58
|
+
* </td>
|
|
59
|
+
* </tr>
|
|
60
|
+
* <tr>
|
|
61
|
+
* <td>Jane Smith</td>
|
|
62
|
+
* <td>jane@example.com</td>
|
|
63
|
+
* <td>
|
|
64
|
+
* <span className="px-2 py-1 bg-yellow-100 text-yellow-800 rounded-full text-xs">
|
|
65
|
+
* Pending
|
|
66
|
+
* </span>
|
|
67
|
+
* </td>
|
|
68
|
+
* </tr>
|
|
69
|
+
* </tbody>
|
|
70
|
+
* </SmartTable>
|
|
71
|
+
*
|
|
72
|
+
* // Large collapsible table with custom styling
|
|
73
|
+
* <SmartTable
|
|
74
|
+
* isRollable
|
|
75
|
+
* className="border border-gray-200 rounded-lg overflow-hidden"
|
|
76
|
+
* >
|
|
77
|
+
* <thead className="bg-gray-50">
|
|
78
|
+
* <tr>
|
|
79
|
+
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
80
|
+
* Product ID
|
|
81
|
+
* </th>
|
|
82
|
+
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
83
|
+
* Name
|
|
84
|
+
* </th>
|
|
85
|
+
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
86
|
+
* Category
|
|
87
|
+
* </th>
|
|
88
|
+
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
89
|
+
* Price
|
|
90
|
+
* </th>
|
|
91
|
+
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
92
|
+
* Stock
|
|
93
|
+
* </th>
|
|
94
|
+
* </tr>
|
|
95
|
+
* </thead>
|
|
96
|
+
* <tbody className="bg-white divide-y divide-gray-200">
|
|
97
|
+
* {products.map((product) => (
|
|
98
|
+
* <tr key={product.id} className="hover:bg-gray-50">
|
|
99
|
+
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
100
|
+
* #{product.id}
|
|
101
|
+
* </td>
|
|
102
|
+
* <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
|
103
|
+
* {product.name}
|
|
104
|
+
* </td>
|
|
105
|
+
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
106
|
+
* {product.category}
|
|
107
|
+
* </td>
|
|
108
|
+
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
109
|
+
* ${product.price.toFixed(2)}
|
|
110
|
+
* </td>
|
|
111
|
+
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
112
|
+
* {product.stock} units
|
|
113
|
+
* </td>
|
|
114
|
+
* </tr>
|
|
115
|
+
* ))}
|
|
116
|
+
* </tbody>
|
|
117
|
+
* </SmartTable>
|
|
118
|
+
*
|
|
119
|
+
* // Financial data table with formatted numbers
|
|
120
|
+
* <SmartTable className="w-full border-collapse">
|
|
121
|
+
* <thead>
|
|
122
|
+
* <tr className="border-b-2 border-gray-300">
|
|
123
|
+
* <th scope="col" className="text-left py-3 px-4">Quarter</th>
|
|
124
|
+
* <th scope="col" className="text-right py-3 px-4">Revenue</th>
|
|
125
|
+
* <th scope="col" className="text-right py-3 px-4">Profit</th>
|
|
126
|
+
* <th scope="col" className="text-right py-3 px-4">Growth</th>
|
|
127
|
+
* </tr>
|
|
128
|
+
* </thead>
|
|
129
|
+
* <tbody>
|
|
130
|
+
* <tr className="border-b border-gray-200">
|
|
131
|
+
* <td className="py-3 px-4 font-medium">Q1 2024</td>
|
|
132
|
+
* <td className="py-3 px-4 text-right">$2,450,000</td>
|
|
133
|
+
* <td className="py-3 px-4 text-right text-green-600">$345,000</td>
|
|
134
|
+
* <td className="py-3 px-4 text-right text-green-600">+12.5%</td>
|
|
135
|
+
* </tr>
|
|
136
|
+
* <tr className="border-b border-gray-200">
|
|
137
|
+
* <td className="py-3 px-4 font-medium">Q2 2024</td>
|
|
138
|
+
* <td className="py-3 px-4 text-right">$2,780,000</td>
|
|
139
|
+
* <td className="py-3 px-4 text-right text-green-600">$398,000</td>
|
|
140
|
+
* <td className="py-3 px-4 text-right text-green-600">+13.5%</td>
|
|
141
|
+
* </tr>
|
|
142
|
+
* </tbody>
|
|
143
|
+
* </SmartTable>
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @see {@link ExpandCollapse} - Component used for collapsible table content
|
|
147
|
+
* @see {@link Modal} - Component used for full-screen table view
|
|
148
|
+
* @see {@link Button} - Component used for the modal trigger button
|
|
149
|
+
*/
|
|
150
|
+
const SmartTable = ({ className, isRollable = false, displayModal, isInteractive, onClick, ...props }) => {
|
|
151
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
152
|
+
const [highlightedRowIndex, setHighlightedRowIndex] = useState(null);
|
|
153
|
+
const tableRef = useRef(null);
|
|
154
|
+
const modalTableRef = useRef(null);
|
|
155
|
+
useTableWidths(tableRef, modalTableRef, [props.children, isModalOpen]);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (isModalOpen && highlightedRowIndex !== null && modalTableRef.current) {
|
|
158
|
+
const row = modalTableRef.current.rows[highlightedRowIndex];
|
|
159
|
+
if (row) {
|
|
160
|
+
row.scrollIntoView({
|
|
161
|
+
behavior: "smooth",
|
|
162
|
+
block: "center"
|
|
163
|
+
});
|
|
164
|
+
row.classList.add("bg-neutral/40", "dark:bg-neutral-dark/40");
|
|
165
|
+
row.style.transition = "background-color 0.3s ease-in-out";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}, [isModalOpen, highlightedRowIndex]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!isModalOpen) setHighlightedRowIndex(null);
|
|
171
|
+
}, [isModalOpen]);
|
|
172
|
+
const handleTableClick = (e) => {
|
|
173
|
+
if (displayModal) {
|
|
174
|
+
const tr = e.target.closest("tr");
|
|
175
|
+
if (tr?.closest("tbody")) {
|
|
176
|
+
setHighlightedRowIndex(tr.rowIndex);
|
|
177
|
+
setIsModalOpen(true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
onClick?.(e);
|
|
181
|
+
};
|
|
182
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
183
|
+
className: "group relative",
|
|
184
|
+
children: [
|
|
185
|
+
displayModal && /* @__PURE__ */ jsx(ExpandButton, { setIsModalOpen }),
|
|
186
|
+
/* @__PURE__ */ jsx(ExpandCollapse, {
|
|
187
|
+
isRollable,
|
|
188
|
+
className: "max-w-full overflow-x-auto rounded-2xl bg-background text-left [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl",
|
|
189
|
+
children: /* @__PURE__ */ jsx(Table, {
|
|
190
|
+
ref: tableRef,
|
|
191
|
+
className,
|
|
192
|
+
isInteractive: isInteractive ?? displayModal,
|
|
193
|
+
onClick: handleTableClick,
|
|
194
|
+
onKeyDown: (e) => {
|
|
195
|
+
if (e.key === "Enter" || e.key === " ") handleTableClick(e);
|
|
196
|
+
},
|
|
197
|
+
...props
|
|
198
|
+
})
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ jsx(Modal, {
|
|
201
|
+
isOpen: isModalOpen,
|
|
202
|
+
onClose: () => setIsModalOpen(false),
|
|
203
|
+
size: ModalSize.XL,
|
|
204
|
+
hasCloseButton: true,
|
|
205
|
+
isScrollable: true,
|
|
206
|
+
children: isModalOpen ? /* @__PURE__ */ jsx("div", {
|
|
207
|
+
className: "grid",
|
|
208
|
+
children: /* @__PURE__ */ jsx(Table, {
|
|
209
|
+
ref: modalTableRef,
|
|
210
|
+
className: cn("min-w-full max-w-full text-left", className),
|
|
211
|
+
isInteractive,
|
|
212
|
+
...props
|
|
213
|
+
})
|
|
214
|
+
}) : /* @__PURE__ */ jsx(Fragment$1, {})
|
|
215
|
+
})
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
//#endregion
|
|
221
|
+
export { SmartTable };
|
|
222
|
+
//# sourceMappingURL=SmartTable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartTable.mjs","names":[],"sources":["../../../../src/components/Table/SmartTable.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport {\n type FC,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { ExpandCollapse } from '../ExpandCollapse';\nimport { Modal, ModalSize } from '../Modal';\nimport { ExpandButton } from './ExpandButton';\nimport type { TableProps } from './Table';\nimport { Table } from './Table';\nimport { useTableWidths } from './useTableWidths';\n\n/**\n * Properties for the SmartTable component\n *\n * @interface SmartTableProps\n * @extends {TableProps}\n *\n * @property {boolean} [isRollable] - Whether the table content can be collapsed/expanded using the ExpandCollapse wrapper\n * @property {boolean} [displayModal] - Whether the table should be able to expand into a modal\n */\ntype SmartTableProps = TableProps & {\n isRollable?: boolean;\n displayModal?: boolean;\n};\n\n/**\n * Table component that provides an enhanced table experience with modal expansion and collapsible content\n *\n * The Table component wraps a standard HTML table element with additional functionality:\n * - **Modal Expansion**: Click the diagonal arrow button to view the table in a full-screen modal\n * - **Collapsible Content**: Optionally wrap content in an ExpandCollapse component for space-saving\n * - **Responsive Design**: Handles large tables gracefully with modal overflow\n * - **Sticky Controls**: Table controls remain accessible even when scrolling\n *\n * ## Features\n * - **Modal View**: Full-screen modal for better viewing of large tables\n * - **Expand/Collapse**: Optional collapsible wrapper to save space\n * - **Responsive**: Handles overflow and responsive behavior automatically\n * - **Accessibility**: Maintains proper table semantics and keyboard navigation\n * - **Customizable**: Supports all standard HTML table attributes and styling\n *\n * ## Best Practices\n * - Use semantic HTML table structure (thead, tbody, tfoot)\n * - Provide proper column headers with scope attributes\n * - Use the isRollable prop for large tables that might need space management\n * - Apply consistent styling through the className prop\n * - Consider pagination for very large datasets\n *\n * @param {SmartTableProps} props - The properties for the Table component\n * @returns {JSX.Element} The rendered table with enhanced functionality\n *\n * @example\n * ```tsx\n * // Simple data table\n * <SmartTable>\n * <thead>\n * <tr>\n * <th scope=\"col\">Name</th>\n * <th scope=\"col\">Email</th>\n * <th scope=\"col\">Status</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>John Doe</td>\n * <td>john@example.com</td>\n * <td>\n * <span className=\"px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs\">\n * Active\n * </span>\n * </td>\n * </tr>\n * <tr>\n * <td>Jane Smith</td>\n * <td>jane@example.com</td>\n * <td>\n * <span className=\"px-2 py-1 bg-yellow-100 text-yellow-800 rounded-full text-xs\">\n * Pending\n * </span>\n * </td>\n * </tr>\n * </tbody>\n * </SmartTable>\n *\n * // Large collapsible table with custom styling\n * <SmartTable\n * isRollable\n * className=\"border border-gray-200 rounded-lg overflow-hidden\"\n * >\n * <thead className=\"bg-gray-50\">\n * <tr>\n * <th scope=\"col\" className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase\">\n * Product ID\n * </th>\n * <th scope=\"col\" className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase\">\n * Name\n * </th>\n * <th scope=\"col\" className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase\">\n * Category\n * </th>\n * <th scope=\"col\" className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase\">\n * Price\n * </th>\n * <th scope=\"col\" className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase\">\n * Stock\n * </th>\n * </tr>\n * </thead>\n * <tbody className=\"bg-white divide-y divide-gray-200\">\n * {products.map((product) => (\n * <tr key={product.id} className=\"hover:bg-gray-50\">\n * <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-900\">\n * #{product.id}\n * </td>\n * <td className=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">\n * {product.name}\n * </td>\n * <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\">\n * {product.category}\n * </td>\n * <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-900\">\n * ${product.price.toFixed(2)}\n * </td>\n * <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\">\n * {product.stock} units\n * </td>\n * </tr>\n * ))}\n * </tbody>\n * </SmartTable>\n *\n * // Financial data table with formatted numbers\n * <SmartTable className=\"w-full border-collapse\">\n * <thead>\n * <tr className=\"border-b-2 border-gray-300\">\n * <th scope=\"col\" className=\"text-left py-3 px-4\">Quarter</th>\n * <th scope=\"col\" className=\"text-right py-3 px-4\">Revenue</th>\n * <th scope=\"col\" className=\"text-right py-3 px-4\">Profit</th>\n * <th scope=\"col\" className=\"text-right py-3 px-4\">Growth</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr className=\"border-b border-gray-200\">\n * <td className=\"py-3 px-4 font-medium\">Q1 2024</td>\n * <td className=\"py-3 px-4 text-right\">$2,450,000</td>\n * <td className=\"py-3 px-4 text-right text-green-600\">$345,000</td>\n * <td className=\"py-3 px-4 text-right text-green-600\">+12.5%</td>\n * </tr>\n * <tr className=\"border-b border-gray-200\">\n * <td className=\"py-3 px-4 font-medium\">Q2 2024</td>\n * <td className=\"py-3 px-4 text-right\">$2,780,000</td>\n * <td className=\"py-3 px-4 text-right text-green-600\">$398,000</td>\n * <td className=\"py-3 px-4 text-right text-green-600\">+13.5%</td>\n * </tr>\n * </tbody>\n * </SmartTable>\n * ```\n *\n * @see {@link ExpandCollapse} - Component used for collapsible table content\n * @see {@link Modal} - Component used for full-screen table view\n * @see {@link Button} - Component used for the modal trigger button\n */\nexport const SmartTable: FC<SmartTableProps> = ({\n className,\n isRollable = false,\n displayModal,\n isInteractive,\n onClick,\n ...props\n}) => {\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [highlightedRowIndex, setHighlightedRowIndex] = useState<number | null>(\n null\n );\n\n const tableRef = useRef<HTMLTableElement>(null);\n const modalTableRef = useRef<HTMLTableElement>(null);\n\n useTableWidths(tableRef, modalTableRef, [props.children, isModalOpen]);\n\n useEffect(() => {\n if (isModalOpen && highlightedRowIndex !== null && modalTableRef.current) {\n const row = modalTableRef.current.rows[highlightedRowIndex];\n\n if (row) {\n row.scrollIntoView({ behavior: 'smooth', block: 'center' });\n\n row.classList.add('bg-neutral/40', 'dark:bg-neutral-dark/40');\n row.style.transition = 'background-color 0.3s ease-in-out';\n }\n }\n }, [isModalOpen, highlightedRowIndex]);\n\n useEffect(() => {\n if (!isModalOpen) {\n setHighlightedRowIndex(null);\n }\n }, [isModalOpen]);\n\n const handleTableClick = (e: React.MouseEvent<HTMLTableElement>) => {\n if (displayModal) {\n const target = e.target as HTMLElement;\n const tr = target.closest('tr');\n\n if (tr?.closest('tbody')) {\n setHighlightedRowIndex(tr.rowIndex);\n setIsModalOpen(true);\n }\n }\n onClick?.(e);\n };\n\n return (\n <div className=\"group relative\">\n {displayModal && <ExpandButton setIsModalOpen={setIsModalOpen} />}\n\n <ExpandCollapse\n isRollable={isRollable}\n className=\"max-w-full overflow-x-auto rounded-2xl bg-background text-left [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl\"\n >\n <Table\n ref={tableRef}\n className={className}\n isInteractive={isInteractive ?? displayModal}\n onClick={handleTableClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n handleTableClick(\n e as unknown as React.MouseEvent<HTMLTableElement>\n );\n }\n }}\n {...props}\n />\n </ExpandCollapse>\n\n <Modal\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n size={ModalSize.XL}\n hasCloseButton\n isScrollable\n >\n {isModalOpen ? (\n <div className=\"grid\">\n <Table\n ref={modalTableRef}\n className={cn('min-w-full max-w-full text-left', className)}\n isInteractive={isInteractive}\n {...props}\n />\n </div>\n ) : (\n <></>\n )}\n </Modal>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuKA,MAAa,cAAmC,EAC9C,WACA,aAAa,OACb,cACA,eACA,SACA,GAAG,YACC;CACJ,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,qBAAqB,0BAA0B,SACpD,KACD;CAED,MAAM,WAAW,OAAyB,KAAK;CAC/C,MAAM,gBAAgB,OAAyB,KAAK;AAEpD,gBAAe,UAAU,eAAe,CAAC,MAAM,UAAU,YAAY,CAAC;AAEtE,iBAAgB;AACd,MAAI,eAAe,wBAAwB,QAAQ,cAAc,SAAS;GACxE,MAAM,MAAM,cAAc,QAAQ,KAAK;AAEvC,OAAI,KAAK;AACP,QAAI,eAAe;KAAE,UAAU;KAAU,OAAO;KAAU,CAAC;AAE3D,QAAI,UAAU,IAAI,iBAAiB,0BAA0B;AAC7D,QAAI,MAAM,aAAa;;;IAG1B,CAAC,aAAa,oBAAoB,CAAC;AAEtC,iBAAgB;AACd,MAAI,CAAC,YACH,wBAAuB,KAAK;IAE7B,CAAC,YAAY,CAAC;CAEjB,MAAM,oBAAoB,MAA0C;AAClE,MAAI,cAAc;GAEhB,MAAM,KADS,EAAE,OACC,QAAQ,KAAK;AAE/B,OAAI,IAAI,QAAQ,QAAQ,EAAE;AACxB,2BAAuB,GAAG,SAAS;AACnC,mBAAe,KAAK;;;AAGxB,YAAU,EAAE;;AAGd,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,gBAAgB,oBAAC,cAAD,EAA8B,gBAAkB;GAEjE,oBAAC,gBAAD;IACc;IACZ,WAAU;cAEV,oBAAC,OAAD;KACE,KAAK;KACM;KACX,eAAe,iBAAiB;KAChC,SAAS;KACT,YAAY,MAAM;AAChB,UAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,IACjC,kBACE,EACD;;KAGL,GAAI;KACJ;IACa;GAEjB,oBAAC,OAAD;IACE,QAAQ;IACR,eAAe,eAAe,MAAM;IACpC,MAAM,UAAU;IAChB;IACA;cAEC,cACC,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,OAAD;MACE,KAAK;MACL,WAAW,GAAG,mCAAmC,UAAU;MAC5C;MACf,GAAI;MACJ;KACE,IAEN,kCAAK;IAED;GACJ"}
|
|
@@ -1,218 +1,13 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { ExpandButton } from "./ExpandButton.mjs";
|
|
7
|
-
import { useTableWidths } from "./useTableWidths.mjs";
|
|
8
|
-
import { useEffect, useRef, useState } from "react";
|
|
9
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
4
|
|
|
11
5
|
//#region src/components/Table/Table.tsx
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* - **Collapsible Content**: Optionally wrap content in an ExpandCollapse component for space-saving
|
|
18
|
-
* - **Responsive Design**: Handles large tables gracefully with modal overflow
|
|
19
|
-
* - **Sticky Controls**: Table controls remain accessible even when scrolling
|
|
20
|
-
*
|
|
21
|
-
* ## Features
|
|
22
|
-
* - **Modal View**: Full-screen modal for better viewing of large tables
|
|
23
|
-
* - **Expand/Collapse**: Optional collapsible wrapper to save space
|
|
24
|
-
* - **Responsive**: Handles overflow and responsive behavior automatically
|
|
25
|
-
* - **Accessibility**: Maintains proper table semantics and keyboard navigation
|
|
26
|
-
* - **Customizable**: Supports all standard HTML table attributes and styling
|
|
27
|
-
*
|
|
28
|
-
* ## Best Practices
|
|
29
|
-
* - Use semantic HTML table structure (thead, tbody, tfoot)
|
|
30
|
-
* - Provide proper column headers with scope attributes
|
|
31
|
-
* - Use the isRollable prop for large tables that might need space management
|
|
32
|
-
* - Apply consistent styling through the className prop
|
|
33
|
-
* - Consider pagination for very large datasets
|
|
34
|
-
*
|
|
35
|
-
* @param {TableProps} props - The properties for the Table component
|
|
36
|
-
* @returns {JSX.Element} The rendered table with enhanced functionality
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```tsx
|
|
40
|
-
* // Simple data table
|
|
41
|
-
* <Table>
|
|
42
|
-
* <thead>
|
|
43
|
-
* <tr>
|
|
44
|
-
* <th scope="col">Name</th>
|
|
45
|
-
* <th scope="col">Email</th>
|
|
46
|
-
* <th scope="col">Status</th>
|
|
47
|
-
* </tr>
|
|
48
|
-
* </thead>
|
|
49
|
-
* <tbody>
|
|
50
|
-
* <tr>
|
|
51
|
-
* <td>John Doe</td>
|
|
52
|
-
* <td>john@example.com</td>
|
|
53
|
-
* <td>
|
|
54
|
-
* <span className="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">
|
|
55
|
-
* Active
|
|
56
|
-
* </span>
|
|
57
|
-
* </td>
|
|
58
|
-
* </tr>
|
|
59
|
-
* <tr>
|
|
60
|
-
* <td>Jane Smith</td>
|
|
61
|
-
* <td>jane@example.com</td>
|
|
62
|
-
* <td>
|
|
63
|
-
* <span className="px-2 py-1 bg-yellow-100 text-yellow-800 rounded-full text-xs">
|
|
64
|
-
* Pending
|
|
65
|
-
* </span>
|
|
66
|
-
* </td>
|
|
67
|
-
* </tr>
|
|
68
|
-
* </tbody>
|
|
69
|
-
* </Table>
|
|
70
|
-
*
|
|
71
|
-
* // Large collapsible table with custom styling
|
|
72
|
-
* <Table
|
|
73
|
-
* isRollable
|
|
74
|
-
* className="border border-gray-200 rounded-lg overflow-hidden"
|
|
75
|
-
* >
|
|
76
|
-
* <thead className="bg-gray-50">
|
|
77
|
-
* <tr>
|
|
78
|
-
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
79
|
-
* Product ID
|
|
80
|
-
* </th>
|
|
81
|
-
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
82
|
-
* Name
|
|
83
|
-
* </th>
|
|
84
|
-
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
85
|
-
* Category
|
|
86
|
-
* </th>
|
|
87
|
-
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
88
|
-
* Price
|
|
89
|
-
* </th>
|
|
90
|
-
* <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
|
91
|
-
* Stock
|
|
92
|
-
* </th>
|
|
93
|
-
* </tr>
|
|
94
|
-
* </thead>
|
|
95
|
-
* <tbody className="bg-white divide-y divide-gray-200">
|
|
96
|
-
* {products.map((product) => (
|
|
97
|
-
* <tr key={product.id} className="hover:bg-gray-50">
|
|
98
|
-
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
99
|
-
* #{product.id}
|
|
100
|
-
* </td>
|
|
101
|
-
* <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
|
102
|
-
* {product.name}
|
|
103
|
-
* </td>
|
|
104
|
-
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
105
|
-
* {product.category}
|
|
106
|
-
* </td>
|
|
107
|
-
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
108
|
-
* ${product.price.toFixed(2)}
|
|
109
|
-
* </td>
|
|
110
|
-
* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
111
|
-
* {product.stock} units
|
|
112
|
-
* </td>
|
|
113
|
-
* </tr>
|
|
114
|
-
* ))}
|
|
115
|
-
* </tbody>
|
|
116
|
-
* </Table>
|
|
117
|
-
*
|
|
118
|
-
* // Financial data table with formatted numbers
|
|
119
|
-
* <Table className="w-full border-collapse">
|
|
120
|
-
* <thead>
|
|
121
|
-
* <tr className="border-b-2 border-gray-300">
|
|
122
|
-
* <th scope="col" className="text-left py-3 px-4">Quarter</th>
|
|
123
|
-
* <th scope="col" className="text-right py-3 px-4">Revenue</th>
|
|
124
|
-
* <th scope="col" className="text-right py-3 px-4">Profit</th>
|
|
125
|
-
* <th scope="col" className="text-right py-3 px-4">Growth</th>
|
|
126
|
-
* </tr>
|
|
127
|
-
* </thead>
|
|
128
|
-
* <tbody>
|
|
129
|
-
* <tr className="border-b border-gray-200">
|
|
130
|
-
* <td className="py-3 px-4 font-medium">Q1 2024</td>
|
|
131
|
-
* <td className="py-3 px-4 text-right">$2,450,000</td>
|
|
132
|
-
* <td className="py-3 px-4 text-right text-green-600">$345,000</td>
|
|
133
|
-
* <td className="py-3 px-4 text-right text-green-600">+12.5%</td>
|
|
134
|
-
* </tr>
|
|
135
|
-
* <tr className="border-b border-gray-200">
|
|
136
|
-
* <td className="py-3 px-4 font-medium">Q2 2024</td>
|
|
137
|
-
* <td className="py-3 px-4 text-right">$2,780,000</td>
|
|
138
|
-
* <td className="py-3 px-4 text-right text-green-600">$398,000</td>
|
|
139
|
-
* <td className="py-3 px-4 text-right text-green-600">+13.5%</td>
|
|
140
|
-
* </tr>
|
|
141
|
-
* </tbody>
|
|
142
|
-
* </Table>
|
|
143
|
-
* ```
|
|
144
|
-
*
|
|
145
|
-
* @see {@link ExpandCollapse} - Component used for collapsible table content
|
|
146
|
-
* @see {@link Modal} - Component used for full-screen table view
|
|
147
|
-
* @see {@link Button} - Component used for the modal trigger button
|
|
148
|
-
*/
|
|
149
|
-
const Table = ({ className, isRollable = false, displayModal, onClick, ...props }) => {
|
|
150
|
-
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
151
|
-
const [highlightedRowIndex, setHighlightedRowIndex] = useState(null);
|
|
152
|
-
const tableRef = useRef(null);
|
|
153
|
-
const modalTableRef = useRef(null);
|
|
154
|
-
useTableWidths(tableRef, modalTableRef, [props.children, isModalOpen]);
|
|
155
|
-
useEffect(() => {
|
|
156
|
-
if (isModalOpen && highlightedRowIndex !== null && modalTableRef.current) {
|
|
157
|
-
const row = modalTableRef.current.rows[highlightedRowIndex];
|
|
158
|
-
if (row) {
|
|
159
|
-
row.scrollIntoView({
|
|
160
|
-
behavior: "smooth",
|
|
161
|
-
block: "center"
|
|
162
|
-
});
|
|
163
|
-
row.classList.add("bg-neutral/40", "dark:bg-neutral-dark/40");
|
|
164
|
-
row.style.transition = "background-color 0.3s ease-in-out";
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}, [isModalOpen, highlightedRowIndex]);
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (!isModalOpen) setHighlightedRowIndex(null);
|
|
170
|
-
}, [isModalOpen]);
|
|
171
|
-
const handleTableClick = (e) => {
|
|
172
|
-
if (displayModal) {
|
|
173
|
-
const tr = e.target.closest("tr");
|
|
174
|
-
if (tr?.closest("tbody")) {
|
|
175
|
-
setHighlightedRowIndex(tr.rowIndex);
|
|
176
|
-
setIsModalOpen(true);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
onClick?.(e);
|
|
180
|
-
};
|
|
181
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
182
|
-
className: "group relative",
|
|
183
|
-
children: [
|
|
184
|
-
displayModal && /* @__PURE__ */ jsx(ExpandButton, { setIsModalOpen }),
|
|
185
|
-
/* @__PURE__ */ jsx(ExpandCollapse, {
|
|
186
|
-
isRollable,
|
|
187
|
-
className: "max-w-full overflow-x-auto rounded-2xl bg-background text-left [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl",
|
|
188
|
-
children: /* @__PURE__ */ jsx("table", {
|
|
189
|
-
ref: tableRef,
|
|
190
|
-
className: cn("w-full table-auto overflow-hidden", displayModal && "[&_tbody_tr:hover]:bg-neutral/40 [&_tbody_tr:hover]:dark:bg-neutral-dark/40 [&_tbody_tr]:cursor-pointer [&_tbody_tr]:transition-colors", className),
|
|
191
|
-
onClick: handleTableClick,
|
|
192
|
-
onKeyDown: (e) => {
|
|
193
|
-
if (e.key === "Enter" || e.key === " ") handleTableClick(e);
|
|
194
|
-
},
|
|
195
|
-
...props
|
|
196
|
-
})
|
|
197
|
-
}),
|
|
198
|
-
/* @__PURE__ */ jsx(Modal, {
|
|
199
|
-
isOpen: isModalOpen,
|
|
200
|
-
onClose: () => setIsModalOpen(false),
|
|
201
|
-
size: ModalSize.XL,
|
|
202
|
-
hasCloseButton: true,
|
|
203
|
-
isScrollable: true,
|
|
204
|
-
children: isModalOpen ? /* @__PURE__ */ jsx("div", {
|
|
205
|
-
className: "grid",
|
|
206
|
-
children: /* @__PURE__ */ jsx("table", {
|
|
207
|
-
ref: modalTableRef,
|
|
208
|
-
className: cn("min-w-full max-w-full table-auto text-left", className),
|
|
209
|
-
...props
|
|
210
|
-
})
|
|
211
|
-
}) : /* @__PURE__ */ jsx(Fragment$1, {})
|
|
212
|
-
})
|
|
213
|
-
]
|
|
214
|
-
});
|
|
215
|
-
};
|
|
6
|
+
const Table = forwardRef(({ className, isInteractive, ...props }, ref) => /* @__PURE__ */ jsx("table", {
|
|
7
|
+
ref,
|
|
8
|
+
className: cn("w-full table-auto overflow-hidden text-left", isInteractive && "[&_tbody_tr:hover]:bg-neutral/40 [&_tbody_tr:hover]:dark:bg-neutral-dark/40 [&_tbody_tr]:cursor-pointer [&_tbody_tr]:transition-colors", className),
|
|
9
|
+
...props
|
|
10
|
+
}));
|
|
216
11
|
|
|
217
12
|
//#endregion
|
|
218
13
|
export { Table };
|