@intlayer/design-system 7.3.3 → 7.3.5

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 (108) hide show
  1. package/dist/esm/components/IDE/IDE.mjs +1 -1
  2. package/dist/esm/components/IDE/IDE.mjs.map +1 -1
  3. package/dist/esm/components/Modal/Modal.mjs +2 -2
  4. package/dist/esm/components/Modal/Modal.mjs.map +1 -1
  5. package/dist/esm/components/Navbar/MobileNavbar.mjs +6 -6
  6. package/dist/esm/components/Navbar/MobileNavbar.mjs.map +1 -1
  7. package/dist/esm/components/Navbar/index.mjs +3 -2
  8. package/dist/esm/components/Navbar/index.mjs.map +1 -1
  9. package/dist/esm/components/WithResizer/index.mjs +46 -19
  10. package/dist/esm/components/WithResizer/index.mjs.map +1 -1
  11. package/dist/esm/hooks/index.mjs +2 -1
  12. package/dist/esm/hooks/useGetElementById.mjs +16 -0
  13. package/dist/esm/hooks/useGetElementById.mjs.map +1 -0
  14. package/dist/esm/hooks/useScrollY.mjs +23 -6
  15. package/dist/esm/hooks/useScrollY.mjs.map +1 -1
  16. package/dist/types/components/Badge/index.d.ts +2 -2
  17. package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
  18. package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts.map +1 -1
  19. package/dist/types/components/Breadcrumb/index.d.ts +2 -2
  20. package/dist/types/components/Breadcrumb/index.d.ts.map +1 -1
  21. package/dist/types/components/Browser/Browser.content.d.ts +11 -11
  22. package/dist/types/components/Button/Button.d.ts +7 -7
  23. package/dist/types/components/Button/Button.d.ts.map +1 -1
  24. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +4 -4
  25. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
  26. package/dist/types/components/Command/index.d.ts +20 -20
  27. package/dist/types/components/Container/index.d.ts +8 -8
  28. package/dist/types/components/Container/index.d.ts.map +1 -1
  29. package/dist/types/components/CopyButton/CopyButton.content.d.ts +3 -3
  30. package/dist/types/components/CopyButton/CopyButton.content.d.ts.map +1 -1
  31. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +25 -25
  32. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts +9 -9
  33. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +33 -33
  34. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/useDictionaryDetailsSchema.content.d.ts +25 -25
  35. package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
  36. package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts.map +1 -1
  37. package/dist/types/components/DictionaryFieldEditor/SaveForm/saveForm.content.d.ts +33 -33
  38. package/dist/types/components/DictionaryFieldEditor/StructureView/structureView.content.d.ts +9 -9
  39. package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts +7 -7
  40. package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts.map +1 -1
  41. package/dist/types/components/DictionaryFieldEditor/dictionaryFieldEditor.content.d.ts +5 -5
  42. package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
  43. package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts.map +1 -1
  44. package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
  45. package/dist/types/components/Form/FormBase.d.ts +2 -2
  46. package/dist/types/components/Form/FormBase.d.ts.map +1 -1
  47. package/dist/types/components/Form/FormField.d.ts +2 -2
  48. package/dist/types/components/Form/FormField.d.ts.map +1 -1
  49. package/dist/types/components/Form/FormItem.d.ts +2 -2
  50. package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +2 -2
  51. package/dist/types/components/Form/elements/FormElement.d.ts +2 -2
  52. package/dist/types/components/Form/elements/OTPElement.d.ts +2 -2
  53. package/dist/types/components/Form/elements/SelectElement.d.ts +2 -2
  54. package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +2 -2
  55. package/dist/types/components/IDE/code.content.d.ts +5 -5
  56. package/dist/types/components/IDE/code.content.d.ts.map +1 -1
  57. package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
  58. package/dist/types/components/Input/Checkbox.d.ts +5 -5
  59. package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
  60. package/dist/types/components/Input/Input.d.ts +3 -3
  61. package/dist/types/components/Input/Input.d.ts.map +1 -1
  62. package/dist/types/components/Input/OTPInput.d.ts +7 -7
  63. package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
  64. package/dist/types/components/Input/SearchInput.d.ts +2 -2
  65. package/dist/types/components/Link/Link.d.ts +4 -4
  66. package/dist/types/components/Link/Link.d.ts.map +1 -1
  67. package/dist/types/components/Loader/index.content.d.ts +3 -3
  68. package/dist/types/components/Loader/index.content.d.ts.map +1 -1
  69. package/dist/types/components/Loader/spinner.d.ts.map +1 -1
  70. package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts +17 -17
  71. package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts +13 -13
  72. package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts.map +1 -1
  73. package/dist/types/components/MaxWidthSmoother/index.d.ts +2 -2
  74. package/dist/types/components/MaxWidthSmoother/index.d.ts.map +1 -1
  75. package/dist/types/components/Modal/Modal.d.ts.map +1 -1
  76. package/dist/types/components/Navbar/Burger.d.ts +2 -2
  77. package/dist/types/components/Navbar/DesktopNavbar.d.ts +2 -2
  78. package/dist/types/components/Navbar/DesktopNavbar.d.ts.map +1 -1
  79. package/dist/types/components/Navbar/MobileNavbar.d.ts +9 -6
  80. package/dist/types/components/Navbar/MobileNavbar.d.ts.map +1 -1
  81. package/dist/types/components/Navbar/index.d.ts +6 -3
  82. package/dist/types/components/Navbar/index.d.ts.map +1 -1
  83. package/dist/types/components/Pagination/Pagination.d.ts +3 -3
  84. package/dist/types/components/Pagination/pagination.content.d.ts +11 -11
  85. package/dist/types/components/Popover/static.d.ts +3 -3
  86. package/dist/types/components/Popover/static.d.ts.map +1 -1
  87. package/dist/types/components/RightDrawer/useRightDrawerStore.d.ts +2 -2
  88. package/dist/types/components/Select/Select.d.ts +3 -3
  89. package/dist/types/components/Select/Select.d.ts.map +1 -1
  90. package/dist/types/components/SocialNetworks/index.d.ts +2 -2
  91. package/dist/types/components/SwitchSelector/index.d.ts +3 -3
  92. package/dist/types/components/Tab/Tab.d.ts +5 -5
  93. package/dist/types/components/Tab/TabContext.d.ts +2 -2
  94. package/dist/types/components/TabSelector/TabSelector.d.ts +4 -4
  95. package/dist/types/components/Table/table.content.d.ts +3 -3
  96. package/dist/types/components/Tag/index.d.ts +5 -5
  97. package/dist/types/components/Toaster/Toast.d.ts +3 -3
  98. package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
  99. package/dist/types/components/Toaster/Toaster.d.ts +2 -2
  100. package/dist/types/components/WithResizer/index.d.ts +2 -0
  101. package/dist/types/components/WithResizer/index.d.ts.map +1 -1
  102. package/dist/types/hooks/index.d.ts +2 -1
  103. package/dist/types/hooks/useGetElementById.d.ts +5 -0
  104. package/dist/types/hooks/useGetElementById.d.ts.map +1 -0
  105. package/dist/types/hooks/useScrollBlockage/useScrollBlockageStore.d.ts +2 -2
  106. package/dist/types/hooks/useScrollY.d.ts +4 -1
  107. package/dist/types/hooks/useScrollY.d.ts.map +1 -1
  108. package/package.json +14 -14
@@ -37,7 +37,7 @@ const IDE = ({ pages: initialPages, isDarkMode, className, activeTab: defaultAct
37
37
  transparency: "none",
38
38
  ...props,
39
39
  children: [/* @__PURE__ */ jsxs("div", {
40
- className: "flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-neutral text-xs dark:bg-neutral-950",
40
+ className: "flex w-auto flex-row items-center justify-start gap-1 bg-neutral-200 text-neutral text-xs dark:bg-neutral-950",
41
41
  children: [/* @__PURE__ */ jsxs("div", {
42
42
  className: "mx-2 flex items-center justify-start gap-2 p-1",
43
43
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"IDE.mjs","names":["IDE: FC<IDEProps>","path"],"sources":["../../../../src/components/IDE/IDE.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type HTMLAttributes, useEffect, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Container } from '../Container';\nimport { WithResizer } from '../WithResizer';\nimport { FileTree } from './FileTree';\nimport { MarkdownRenderer } from './MarkDownRender';\n\nexport type IDEProps = {\n pages: {\n path: string;\n content: string;\n isOpen?: boolean;\n }[];\n isDarkMode?: boolean;\n activeTab?: number;\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const IDE: FC<IDEProps> = ({\n pages: initialPages,\n isDarkMode,\n className,\n activeTab: defaultActiveTab,\n ...props\n}) => {\n const [pages, setPages] = useState(initialPages);\n const tabs = pages.filter(({ isOpen }) => isOpen);\n\n const firstTabIndex = tabs.findIndex(({ isOpen }) => isOpen);\n const [activeTab, setActiveTab] = useState(defaultActiveTab ?? firstTabIndex);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab ?? firstTabIndex);\n }, [initialPages, defaultActiveTab]);\n\n const { content, path } = pages[activeTab];\n const filePaths = initialPages.map(({ path: title }) => title);\n\n const handleClickFile = (title: string) => {\n const page = pages.find(({ path: tabTitle }) => tabTitle === title);\n if (!page) return;\n\n const newPages = pages.map((page) => {\n if (page.path === title) {\n return { ...page, isOpen: true };\n }\n return page;\n });\n\n setPages(newPages);\n\n const newPageIndex = newPages.findIndex(\n ({ path: tabTitle }) => tabTitle === title\n );\n\n setActiveTab(newPageIndex);\n };\n\n return (\n <Container\n className={cn(\n 'flex size-full flex-col justify-start overflow-hidden shadow-lg',\n className\n )}\n roundedSize=\"3xl\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-neutral text-xs dark:bg-neutral-950\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-red-500\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n <div className=\"flex size-full overflow-y-auto\">\n {tabs.map(({ path }, index) => {\n const fullPath = path.split('/');\n const title = fullPath[fullPath.length - 1];\n const isActive = index === activeTab;\n\n return (\n <button\n className={cn(\n 'flex h-8 min-w-20 items-center justify-start px-3 py-1 transition',\n isActive\n ? 'bg-card'\n : 'cursor-pointer bg-neutral-200 hover:bg-neutral-300 dark:bg-neutral-950'\n )}\n key={title}\n onClick={() => setActiveTab(index)}\n >\n {title}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <WithResizer initialWidth={150}>\n <FileTree\n filesPaths={filePaths}\n activeFile={path}\n onClickFile={handleClickFile}\n />\n </WithResizer>\n\n <div className=\"size-full flex-1 overflow-auto pt-2 text-xs\">\n <MarkdownRenderer isDarkMode={isDarkMode}>\n {content}\n </MarkdownRenderer>\n </div>\n </div>\n </div>\n </div>\n </Container>\n );\n};\n"],"mappings":";;;;;;;;;;;AAmBA,MAAaA,OAAqB,EAChC,OAAO,cACP,YACA,WACA,WAAW,kBACX,GAAG,YACC;CACJ,MAAM,CAAC,OAAO,YAAY,SAAS,aAAa;CAChD,MAAM,OAAO,MAAM,QAAQ,EAAE,aAAa,OAAO;CAEjD,MAAM,gBAAgB,KAAK,WAAW,EAAE,aAAa,OAAO;CAC5D,MAAM,CAAC,WAAW,gBAAgB,SAAS,oBAAoB,cAAc;AAE7E,iBAAgB;AACd,eAAa,oBAAoB,cAAc;IAC9C,CAAC,cAAc,iBAAiB,CAAC;CAEpC,MAAM,EAAE,SAAS,SAAS,MAAM;CAChC,MAAM,YAAY,aAAa,KAAK,EAAE,MAAM,YAAY,MAAM;CAE9D,MAAM,mBAAmB,UAAkB;AAEzC,MAAI,CADS,MAAM,MAAM,EAAE,MAAM,eAAe,aAAa,MAAM,CACxD;EAEX,MAAM,WAAW,MAAM,KAAK,SAAS;AACnC,OAAI,KAAK,SAAS,MAChB,QAAO;IAAE,GAAG;IAAM,QAAQ;IAAM;AAElC,UAAO;IACP;AAEF,WAAS,SAAS;AAMlB,eAJqB,SAAS,WAC3B,EAAE,MAAM,eAAe,aAAa,MACtC,CAEyB;;AAG5B,QACE,qBAAC;EACC,WAAW,GACT,mEACA,UACD;EACD,aAAY;EACZ,cAAa;EACb,GAAI;aAEJ,qBAAC;GAAI,WAAU;cACb,qBAAC;IAAI,WAAU;;KACb,oBAAC,SAAI,WAAU,mCAAmC;KAClD,oBAAC,SAAI,WAAU,sCAAsC;KACrD,oBAAC,SAAI,WAAU,qCAAqC;;KAChD,EACN,oBAAC;IAAI,WAAU;cACZ,KAAK,KAAK,EAAE,gBAAQ,UAAU;KAC7B,MAAM,WAAWC,OAAK,MAAM,IAAI;KAChC,MAAM,QAAQ,SAAS,SAAS,SAAS;AAGzC,YACE,oBAAC;MACC,WAAW,GACT,qEALW,UAAU,YAOjB,YACA,yEACL;MAED,eAAe,aAAa,MAAM;gBAEjC;QAHI,MAIE;MAEX;KACE;IACF,EACN,oBAAC;GAAI,WAAU;aACb,oBAAC;IAAI,WAAU;cACb,qBAAC;KAAI,WAAU;gBACb,oBAAC;MAAY,cAAc;gBACzB,oBAAC;OACC,YAAY;OACZ,YAAY;OACZ,aAAa;QACb;OACU,EAEd,oBAAC;MAAI,WAAU;gBACb,oBAAC;OAA6B;iBAC3B;QACgB;OACf;MACF;KACF;IACF;GACI"}
1
+ {"version":3,"file":"IDE.mjs","names":["IDE: FC<IDEProps>","path"],"sources":["../../../../src/components/IDE/IDE.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type HTMLAttributes, useEffect, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Container } from '../Container';\nimport { WithResizer } from '../WithResizer';\nimport { FileTree } from './FileTree';\nimport { MarkdownRenderer } from './MarkDownRender';\n\nexport type IDEProps = {\n pages: {\n path: string;\n content: string;\n isOpen?: boolean;\n }[];\n isDarkMode?: boolean;\n activeTab?: number;\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const IDE: FC<IDEProps> = ({\n pages: initialPages,\n isDarkMode,\n className,\n activeTab: defaultActiveTab,\n ...props\n}) => {\n const [pages, setPages] = useState(initialPages);\n const tabs = pages.filter(({ isOpen }) => isOpen);\n\n const firstTabIndex = tabs.findIndex(({ isOpen }) => isOpen);\n const [activeTab, setActiveTab] = useState(defaultActiveTab ?? firstTabIndex);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab ?? firstTabIndex);\n }, [initialPages, defaultActiveTab]);\n\n const { content, path } = pages[activeTab];\n const filePaths = initialPages.map(({ path: title }) => title);\n\n const handleClickFile = (title: string) => {\n const page = pages.find(({ path: tabTitle }) => tabTitle === title);\n if (!page) return;\n\n const newPages = pages.map((page) => {\n if (page.path === title) {\n return { ...page, isOpen: true };\n }\n return page;\n });\n\n setPages(newPages);\n\n const newPageIndex = newPages.findIndex(\n ({ path: tabTitle }) => tabTitle === title\n );\n\n setActiveTab(newPageIndex);\n };\n\n return (\n <Container\n className={cn(\n 'flex size-full flex-col justify-start overflow-hidden shadow-lg',\n className\n )}\n roundedSize=\"3xl\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 bg-neutral-200 text-neutral text-xs dark:bg-neutral-950\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-red-500\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n <div className=\"flex size-full overflow-y-auto\">\n {tabs.map(({ path }, index) => {\n const fullPath = path.split('/');\n const title = fullPath[fullPath.length - 1];\n const isActive = index === activeTab;\n\n return (\n <button\n className={cn(\n 'flex h-8 min-w-20 items-center justify-start px-3 py-1 transition',\n isActive\n ? 'bg-card'\n : 'cursor-pointer bg-neutral-200 hover:bg-neutral-300 dark:bg-neutral-950'\n )}\n key={title}\n onClick={() => setActiveTab(index)}\n >\n {title}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <WithResizer initialWidth={150}>\n <FileTree\n filesPaths={filePaths}\n activeFile={path}\n onClickFile={handleClickFile}\n />\n </WithResizer>\n\n <div className=\"size-full flex-1 overflow-auto pt-2 text-xs\">\n <MarkdownRenderer isDarkMode={isDarkMode}>\n {content}\n </MarkdownRenderer>\n </div>\n </div>\n </div>\n </div>\n </Container>\n );\n};\n"],"mappings":";;;;;;;;;;;AAmBA,MAAaA,OAAqB,EAChC,OAAO,cACP,YACA,WACA,WAAW,kBACX,GAAG,YACC;CACJ,MAAM,CAAC,OAAO,YAAY,SAAS,aAAa;CAChD,MAAM,OAAO,MAAM,QAAQ,EAAE,aAAa,OAAO;CAEjD,MAAM,gBAAgB,KAAK,WAAW,EAAE,aAAa,OAAO;CAC5D,MAAM,CAAC,WAAW,gBAAgB,SAAS,oBAAoB,cAAc;AAE7E,iBAAgB;AACd,eAAa,oBAAoB,cAAc;IAC9C,CAAC,cAAc,iBAAiB,CAAC;CAEpC,MAAM,EAAE,SAAS,SAAS,MAAM;CAChC,MAAM,YAAY,aAAa,KAAK,EAAE,MAAM,YAAY,MAAM;CAE9D,MAAM,mBAAmB,UAAkB;AAEzC,MAAI,CADS,MAAM,MAAM,EAAE,MAAM,eAAe,aAAa,MAAM,CACxD;EAEX,MAAM,WAAW,MAAM,KAAK,SAAS;AACnC,OAAI,KAAK,SAAS,MAChB,QAAO;IAAE,GAAG;IAAM,QAAQ;IAAM;AAElC,UAAO;IACP;AAEF,WAAS,SAAS;AAMlB,eAJqB,SAAS,WAC3B,EAAE,MAAM,eAAe,aAAa,MACtC,CAEyB;;AAG5B,QACE,qBAAC;EACC,WAAW,GACT,mEACA,UACD;EACD,aAAY;EACZ,cAAa;EACb,GAAI;aAEJ,qBAAC;GAAI,WAAU;cACb,qBAAC;IAAI,WAAU;;KACb,oBAAC,SAAI,WAAU,mCAAmC;KAClD,oBAAC,SAAI,WAAU,sCAAsC;KACrD,oBAAC,SAAI,WAAU,qCAAqC;;KAChD,EACN,oBAAC;IAAI,WAAU;cACZ,KAAK,KAAK,EAAE,gBAAQ,UAAU;KAC7B,MAAM,WAAWC,OAAK,MAAM,IAAI;KAChC,MAAM,QAAQ,SAAS,SAAS,SAAS;AAGzC,YACE,oBAAC;MACC,WAAW,GACT,qEALW,UAAU,YAOjB,YACA,yEACL;MAED,eAAe,aAAa,MAAM;gBAEjC;QAHI,MAIE;MAEX;KACE;IACF,EACN,oBAAC;GAAI,WAAU;aACb,oBAAC;IAAI,WAAU;cACb,qBAAC;KAAI,WAAU;gBACb,oBAAC;MAAY,cAAc;gBACzB,oBAAC;OACC,YAAY;OACZ,YAAY;OACZ,aAAa;QACb;OACU,EAEd,oBAAC;MAAI,WAAU;gBACb,oBAAC;OAA6B;iBAC3B;QACgB;OACf;MACF;KACF;IACF;GACI"}
@@ -34,7 +34,7 @@ let ModalSize = /* @__PURE__ */ function(ModalSize$1) {
34
34
  * Class name variants for different modal sizes using class-variance-authority
35
35
  * Defines responsive sizing and scrollable content for modal containers
36
36
  */
37
- const modalVariants = cva("cursor-default overflow-auto p-3 shadow-sm", {
37
+ const modalVariants = cva("flex cursor-default flex-col overflow-hidden p-3 shadow-sm", {
38
38
  variants: { size: {
39
39
  sm: "h-auto max-h-[30vh] w-[95vw] max-w-xl",
40
40
  md: "h-auto max-h-[50vh] w-[95vw] max-w-xl",
@@ -190,7 +190,7 @@ const Modal = ({ children, isOpen, container, disableScroll = true, onClose, has
190
190
  size: ButtonSize.ICON_MD
191
191
  })]
192
192
  }), /* @__PURE__ */ jsx("div", {
193
- className: "flex flex-1 flex-col items-center",
193
+ className: "flex w-full flex-1 flex-col overflow-hidden",
194
194
  children
195
195
  })]
196
196
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.mjs","names":["m","Modal: FC<ModalProps>"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { motion as m } from 'framer-motion';\nimport { X } from 'lucide-react';\nimport { type FC, type ReactNode, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useGetElementOrWindow, useScrollBlockage } from '../../hooks/index';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container, type ContainerProps } from '../Container';\nimport { H3 } from '../Headers';\n\n/**\n * Enumeration of available modal sizes\n */\nexport enum ModalSize {\n /** Small modal: max height 30vh, max width xl */\n SM = 'sm',\n /** Medium modal: max height 50vh, max width xl */\n MD = 'md',\n /** Large modal: max height 70vh, max width 2xl */\n LG = 'lg',\n /** Extra large modal: max height 95vh, max width 6xl */\n XL = 'xl',\n /** Unset size: max height 95vh, full width responsive */\n UNSET = 'unset',\n}\n\n/**\n * Props for the Modal component\n */\ntype ModalProps = {\n /** Content to be displayed inside the modal */\n children: ReactNode;\n /** Controls whether the modal is visible */\n isOpen: boolean;\n /** Callback function called when the modal should be closed */\n onClose?: () => void;\n /** Container element to render the modal into (defaults to document.body) */\n container?: HTMLElement;\n /** Whether to disable scrolling on the background content */\n disableScroll?: boolean;\n /** Whether to display a close button in the modal header */\n hasCloseButton?: boolean;\n /** Optional title displayed at the top of the modal */\n title?: string;\n /** Size variant for the modal */\n size?: ModalSize | `${ModalSize}`;\n} & Pick<\n ContainerProps,\n | 'className'\n | 'transparency'\n | 'border'\n | 'background'\n | 'roundedSize'\n | 'borderColor'\n | 'padding'\n | 'separator'\n | 'gap'\n>;\n\n/**\n * Class name variants for different modal sizes using class-variance-authority\n * Defines responsive sizing and scrollable content for modal containers\n */\nconst modalVariants = cva('cursor-default overflow-auto p-3 shadow-sm', {\n variants: {\n size: {\n /** Small modal: height auto, max-height 30vh, width 95vw, max-width xl */\n sm: 'h-auto max-h-[30vh] w-[95vw] max-w-xl',\n /** Medium modal: height auto, max-height 50vh, width 95vw, max-width xl */\n md: 'h-auto max-h-[50vh] w-[95vw] max-w-xl',\n /** Large modal: height auto, max-height 70vh, width 95vw, max-width 2xl */\n lg: 'h-auto max-h-[70vh] w-[95vw] max-w-2xl',\n /** Extra large modal: height auto, max-height 95vh, width 95vw, max-width 6xl */\n xl: 'h-auto max-h-[95vh] w-[95vw] max-w-6xl',\n /** Unset modal: height auto, max-height 95vh, width 95vw, no max-width */\n unset: 'h-auto max-h-[95vh] w-[95vw]',\n },\n },\n defaultVariants: {\n size: 'unset',\n },\n});\n\n/**\n * Motion-enabled modal component with Framer Motion support\n * Extends Container component with motion capabilities for animations\n */\nconst MotionModal = m.create(Container);\n\n/**\n * Modal Component\n *\n * A highly customizable modal dialog component with portal rendering, Framer Motion animations,\n * and comprehensive accessibility features. Supports multiple size variants and scroll management.\n *\n * Features:\n * - Portal rendering to any container element (defaults to document.body)\n * - Smooth animations with Framer Motion\n * - Size variants: SM, MD, LG, XL, UNSET with responsive sizing\n * - Optional title and close button\n * - Background scroll prevention\n * - Click-outside-to-close functionality\n * - Full accessibility support with ARIA attributes\n * - Keyboard navigation support (ESC to close)\n * - Extensible styling with Container props\n *\n * @example\n * Basic usage:\n * ```jsx\n * <Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>\n * <p>Modal content goes here</p>\n * </Modal>\n * ```\n *\n * @example\n * With title and close button:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * title=\"Confirm Action\"\n * hasCloseButton\n * size={ModalSize.LG}\n * >\n * <div>\n * <p>Are you sure you want to continue?</p>\n * <Button onClick={onConfirm}>Confirm</Button>\n * </div>\n * </Modal>\n * ```\n *\n * @example\n * Custom container and styling:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * container={customContainer}\n * background=\"card\"\n * padding=\"lg\"\n * border=\"default\"\n * >\n * Content with custom styling\n * </Modal>\n * ```\n *\n * Accessibility Notes:\n * - Modal receives focus when opened\n * - Background content is hidden from screen readers when modal is open\n * - ESC key closes modal (handled by browser for role=\"dialog\")\n * - Click outside modal closes it\n * - Close button has descriptive label for screen readers\n *\n * @param props - Modal component props\n * @returns JSX element rendered via createPortal\n */\nexport const Modal: FC<ModalProps> = ({\n children,\n isOpen,\n container,\n disableScroll = true,\n onClose,\n hasCloseButton = false,\n title,\n size = ModalSize.MD,\n className,\n ...props\n}) => {\n const containerElement = useGetElementOrWindow(container);\n\n useScrollBlockage({ key: 'modal', disableScroll: isOpen && disableScroll });\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && isOpen && onClose) {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!containerElement) return <></>;\n\n const hasTitle = typeof title === 'string';\n\n return createPortal(\n <m.div\n className=\"invisible fixed top-0 left-0 z-50 flex size-full cursor-pointer items-center justify-center overflow-auto bg-background/40 backdrop-blur\"\n animate={isOpen ? 'visible' : 'invisible'}\n variants={{\n visible: {\n opacity: 1,\n visibility: 'visible',\n transition: { duration: 0.1, when: 'beforeChildren' },\n },\n invisible: {\n opacity: 0,\n visibility: 'hidden',\n transition: { duration: 0.1, when: 'afterChildren' },\n },\n }}\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n aria-hidden={!isOpen}\n >\n <MotionModal\n onClick={(e) => e.stopPropagation()}\n initial={{ scale: isOpen ? 0.5 : 1 }}\n animate={{ scale: isOpen ? 1 : 0.5 }}\n transition={{ duration: 0.3 }}\n className={modalVariants({\n size,\n className,\n })}\n role=\"dialog\"\n aria-modal\n roundedSize=\"2xl\"\n {...props}\n >\n <div\n className={cn(\n 'cursor-default',\n hasCloseButton && hasTitle\n ? `flex items-start`\n : hasCloseButton\n ? `flex justify-end`\n : hasTitle\n ? `items-center`\n : `hidden`\n )}\n >\n {hasTitle && (\n <H3 className=\"mt-2 mb-4 ml-4 flex items-center justify-center font-bold text-lg\">\n {title}\n </H3>\n )}\n {hasCloseButton && (\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label=\"Close modal\"\n className=\"ml-auto\"\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n Icon={X}\n size={ButtonSize.ICON_MD}\n />\n )}\n </div>\n <div className=\"flex flex-1 flex-col items-center\">{children}</div>\n </MotionModal>\n </m.div>,\n containerElement\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,IAAY,kDAAL;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;;;;;;AAwCF,MAAM,gBAAgB,IAAI,8CAA8C;CACtE,UAAU,EACR,MAAM;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,OAAO;EACR,EACF;CACD,iBAAiB,EACf,MAAM,SACP;CACF,CAAC;;;;;AAMF,MAAM,cAAcA,OAAE,OAAO,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEvC,MAAaC,SAAyB,EACpC,UACA,QACA,WACA,gBAAgB,MAChB,SACA,iBAAiB,OACjB,OACA,OAAO,UAAU,IACjB,WACA,GAAG,YACC;CACJ,MAAM,mBAAmB,sBAAsB,UAAU;AAEzD,mBAAkB;EAAE,KAAK;EAAS,eAAe,UAAU;EAAe,CAAC;AAE3E,iBAAgB;EACd,MAAM,gBAAgB,UAAyB;AAC7C,OAAI,MAAM,QAAQ,YAAY,UAAU,QACtC,UAAS;;AAIb,WAAS,iBAAiB,WAAW,aAAa;AAElD,eAAa;AACX,YAAS,oBAAoB,WAAW,aAAa;;IAEtD,CAAC,QAAQ,QAAQ,CAAC;AAErB,KAAI,CAAC,iBAAkB,QAAO,mCAAK;CAEnC,MAAM,WAAW,OAAO,UAAU;AAElC,QAAO,aACL,oBAACD,OAAE;EACD,WAAU;EACV,SAAS,SAAS,YAAY;EAC9B,UAAU;GACR,SAAS;IACP,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAkB;IACtD;GACD,WAAW;IACT,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAiB;IACrD;GACF;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,cAAW;;EAEb,eAAa,CAAC;YAEd,qBAAC;GACC,UAAU,MAAM,EAAE,iBAAiB;GACnC,SAAS,EAAE,OAAO,SAAS,KAAM,GAAG;GACpC,SAAS,EAAE,OAAO,SAAS,IAAI,IAAK;GACpC,YAAY,EAAE,UAAU,IAAK;GAC7B,WAAW,cAAc;IACvB;IACA;IACD,CAAC;GACF,MAAK;GACL;GACA,aAAY;GACZ,GAAI;cAEJ,qBAAC;IACC,WAAW,GACT,kBACA,kBAAkB,WACd,qBACA,iBACE,qBACA,WACE,iBACA,SACT;eAEA,YACC,oBAAC;KAAG,WAAU;eACX;MACE,EAEN,kBACC,oBAAC;KACC,SAAS,cAAc;KACvB,OAAO,YAAY;KACnB,OAAM;KACN,WAAU;KACV,UAAU,MAAM;AACd,QAAE,iBAAiB;AACnB,iBAAW;;KAEb,MAAM;KACN,MAAM,WAAW;MACjB;KAEA,EACN,oBAAC;IAAI,WAAU;IAAqC;KAAe;IACvD;GACR,EACR,iBACD"}
1
+ {"version":3,"file":"Modal.mjs","names":["m","Modal: FC<ModalProps>"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { motion as m } from 'framer-motion';\nimport { X } from 'lucide-react';\nimport { type FC, type ReactNode, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useGetElementOrWindow, useScrollBlockage } from '../../hooks/index';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container, type ContainerProps } from '../Container';\nimport { H3 } from '../Headers';\n\n/**\n * Enumeration of available modal sizes\n */\nexport enum ModalSize {\n /** Small modal: max height 30vh, max width xl */\n SM = 'sm',\n /** Medium modal: max height 50vh, max width xl */\n MD = 'md',\n /** Large modal: max height 70vh, max width 2xl */\n LG = 'lg',\n /** Extra large modal: max height 95vh, max width 6xl */\n XL = 'xl',\n /** Unset size: max height 95vh, full width responsive */\n UNSET = 'unset',\n}\n\n/**\n * Props for the Modal component\n */\ntype ModalProps = {\n /** Content to be displayed inside the modal */\n children: ReactNode;\n /** Controls whether the modal is visible */\n isOpen: boolean;\n /** Callback function called when the modal should be closed */\n onClose?: () => void;\n /** Container element to render the modal into (defaults to document.body) */\n container?: HTMLElement;\n /** Whether to disable scrolling on the background content */\n disableScroll?: boolean;\n /** Whether to display a close button in the modal header */\n hasCloseButton?: boolean;\n /** Optional title displayed at the top of the modal */\n title?: string;\n /** Size variant for the modal */\n size?: ModalSize | `${ModalSize}`;\n} & Pick<\n ContainerProps,\n | 'className'\n | 'transparency'\n | 'border'\n | 'background'\n | 'roundedSize'\n | 'borderColor'\n | 'padding'\n | 'separator'\n | 'gap'\n>;\n\n/**\n * Class name variants for different modal sizes using class-variance-authority\n * Defines responsive sizing and scrollable content for modal containers\n */\nconst modalVariants = cva(\n 'flex cursor-default flex-col overflow-hidden p-3 shadow-sm',\n {\n variants: {\n size: {\n /** Small modal: height auto, max-height 30vh, width 95vw, max-width xl */\n sm: 'h-auto max-h-[30vh] w-[95vw] max-w-xl',\n /** Medium modal: height auto, max-height 50vh, width 95vw, max-width xl */\n md: 'h-auto max-h-[50vh] w-[95vw] max-w-xl',\n /** Large modal: height auto, max-height 70vh, width 95vw, max-width 2xl */\n lg: 'h-auto max-h-[70vh] w-[95vw] max-w-2xl',\n /** Extra large modal: height auto, max-height 95vh, width 95vw, max-width 6xl */\n xl: 'h-auto max-h-[95vh] w-[95vw] max-w-6xl',\n /** Unset modal: height auto, max-height 95vh, width 95vw, no max-width */\n unset: 'h-auto max-h-[95vh] w-[95vw]',\n },\n },\n defaultVariants: {\n size: 'unset',\n },\n }\n);\n\n/**\n * Motion-enabled modal component with Framer Motion support\n * Extends Container component with motion capabilities for animations\n */\nconst MotionModal = m.create(Container);\n\n/**\n * Modal Component\n *\n * A highly customizable modal dialog component with portal rendering, Framer Motion animations,\n * and comprehensive accessibility features. Supports multiple size variants and scroll management.\n *\n * Features:\n * - Portal rendering to any container element (defaults to document.body)\n * - Smooth animations with Framer Motion\n * - Size variants: SM, MD, LG, XL, UNSET with responsive sizing\n * - Optional title and close button\n * - Background scroll prevention\n * - Click-outside-to-close functionality\n * - Full accessibility support with ARIA attributes\n * - Keyboard navigation support (ESC to close)\n * - Extensible styling with Container props\n *\n * @example\n * Basic usage:\n * ```jsx\n * <Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>\n * <p>Modal content goes here</p>\n * </Modal>\n * ```\n *\n * @example\n * With title and close button:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * title=\"Confirm Action\"\n * hasCloseButton\n * size={ModalSize.LG}\n * >\n * <div>\n * <p>Are you sure you want to continue?</p>\n * <Button onClick={onConfirm}>Confirm</Button>\n * </div>\n * </Modal>\n * ```\n *\n * @example\n * Custom container and styling:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * container={customContainer}\n * background=\"card\"\n * padding=\"lg\"\n * border=\"default\"\n * >\n * Content with custom styling\n * </Modal>\n * ```\n *\n * Accessibility Notes:\n * - Modal receives focus when opened\n * - Background content is hidden from screen readers when modal is open\n * - ESC key closes modal (handled by browser for role=\"dialog\")\n * - Click outside modal closes it\n * - Close button has descriptive label for screen readers\n *\n * @param props - Modal component props\n * @returns JSX element rendered via createPortal\n */\nexport const Modal: FC<ModalProps> = ({\n children,\n isOpen,\n container,\n disableScroll = true,\n onClose,\n hasCloseButton = false,\n title,\n size = ModalSize.MD,\n className,\n ...props\n}) => {\n const containerElement = useGetElementOrWindow(container);\n\n useScrollBlockage({ key: 'modal', disableScroll: isOpen && disableScroll });\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && isOpen && onClose) {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!containerElement) return <></>;\n\n const hasTitle = typeof title === 'string';\n\n return createPortal(\n <m.div\n className=\"invisible fixed top-0 left-0 z-50 flex size-full cursor-pointer items-center justify-center overflow-auto bg-background/40 backdrop-blur\"\n animate={isOpen ? 'visible' : 'invisible'}\n variants={{\n visible: {\n opacity: 1,\n visibility: 'visible',\n transition: { duration: 0.1, when: 'beforeChildren' },\n },\n invisible: {\n opacity: 0,\n visibility: 'hidden',\n transition: { duration: 0.1, when: 'afterChildren' },\n },\n }}\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n aria-hidden={!isOpen}\n >\n <MotionModal\n onClick={(e) => e.stopPropagation()}\n initial={{ scale: isOpen ? 0.5 : 1 }}\n animate={{ scale: isOpen ? 1 : 0.5 }}\n transition={{ duration: 0.3 }}\n className={modalVariants({\n size,\n className,\n })}\n role=\"dialog\"\n aria-modal\n roundedSize=\"2xl\"\n {...props}\n >\n <div\n className={cn(\n 'cursor-default',\n hasCloseButton && hasTitle\n ? `flex items-start`\n : hasCloseButton\n ? `flex justify-end`\n : hasTitle\n ? `items-center`\n : `hidden`\n )}\n >\n {hasTitle && (\n <H3 className=\"mt-2 mb-4 ml-4 flex items-center justify-center font-bold text-lg\">\n {title}\n </H3>\n )}\n {hasCloseButton && (\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label=\"Close modal\"\n className=\"ml-auto\"\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n Icon={X}\n size={ButtonSize.ICON_MD}\n />\n )}\n </div>\n <div className=\"flex w-full flex-1 flex-col overflow-hidden\">\n {children}\n </div>\n </MotionModal>\n </m.div>,\n containerElement\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,IAAY,kDAAL;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;;;;;;AAwCF,MAAM,gBAAgB,IACpB,8DACA;CACE,UAAU,EACR,MAAM;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,OAAO;EACR,EACF;CACD,iBAAiB,EACf,MAAM,SACP;CACF,CACF;;;;;AAMD,MAAM,cAAcA,OAAE,OAAO,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEvC,MAAaC,SAAyB,EACpC,UACA,QACA,WACA,gBAAgB,MAChB,SACA,iBAAiB,OACjB,OACA,OAAO,UAAU,IACjB,WACA,GAAG,YACC;CACJ,MAAM,mBAAmB,sBAAsB,UAAU;AAEzD,mBAAkB;EAAE,KAAK;EAAS,eAAe,UAAU;EAAe,CAAC;AAE3E,iBAAgB;EACd,MAAM,gBAAgB,UAAyB;AAC7C,OAAI,MAAM,QAAQ,YAAY,UAAU,QACtC,UAAS;;AAIb,WAAS,iBAAiB,WAAW,aAAa;AAElD,eAAa;AACX,YAAS,oBAAoB,WAAW,aAAa;;IAEtD,CAAC,QAAQ,QAAQ,CAAC;AAErB,KAAI,CAAC,iBAAkB,QAAO,mCAAK;CAEnC,MAAM,WAAW,OAAO,UAAU;AAElC,QAAO,aACL,oBAACD,OAAE;EACD,WAAU;EACV,SAAS,SAAS,YAAY;EAC9B,UAAU;GACR,SAAS;IACP,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAkB;IACtD;GACD,WAAW;IACT,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAiB;IACrD;GACF;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,cAAW;;EAEb,eAAa,CAAC;YAEd,qBAAC;GACC,UAAU,MAAM,EAAE,iBAAiB;GACnC,SAAS,EAAE,OAAO,SAAS,KAAM,GAAG;GACpC,SAAS,EAAE,OAAO,SAAS,IAAI,IAAK;GACpC,YAAY,EAAE,UAAU,IAAK;GAC7B,WAAW,cAAc;IACvB;IACA;IACD,CAAC;GACF,MAAK;GACL;GACA,aAAY;GACZ,GAAI;cAEJ,qBAAC;IACC,WAAW,GACT,kBACA,kBAAkB,WACd,qBACA,iBACE,qBACA,WACE,iBACA,SACT;eAEA,YACC,oBAAC;KAAG,WAAU;eACX;MACE,EAEN,kBACC,oBAAC;KACC,SAAS,cAAc;KACvB,OAAO,YAAY;KACnB,OAAM;KACN,WAAU;KACV,UAAU,MAAM;AACd,QAAE,iBAAiB;AACnB,iBAAW;;KAEb,MAAM;KACN,MAAM,WAAW;MACjB;KAEA,EACN,oBAAC;IAAI,WAAU;IACZ;KACG;IACM;GACR,EACR,iBACD"}
@@ -32,12 +32,12 @@ const bgStyle = "bg-card/95 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blu
32
32
  /**
33
33
  * Mobile Navigation Bar Component
34
34
  *
35
- * A sophisticated mobile-first navigation component with collapsible full-screen menu,
35
+ * A sophisticated mobile-first navigation component with rollable full-screen menu,
36
36
  * scroll-aware behavior, and smooth animations. Optimized for touch interactions and
37
37
  * mobile user experience patterns.
38
38
  *
39
39
  * Features:
40
- * - Collapsible hamburger menu with full-screen overlay
40
+ * - rollable hamburger menu with full-screen overlay
41
41
  * - Auto-hide on scroll down, show on scroll up for screen space optimization
42
42
  * - Background scroll prevention when menu is open
43
43
  * - Staggered animations for smooth menu item reveals
@@ -105,20 +105,20 @@ const bgStyle = "bg-card/95 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blu
105
105
  *
106
106
  * @template T - Tab properties type extending TabProps for type safety
107
107
  * @param props - MobileNavbar component props
108
- * @returns Mobile navigation with collapsible full-screen menu
108
+ * @returns Mobile navigation with rollable full-screen menu
109
109
  */
110
- const MobileNavbar = ({ logo, topChildren, topSections = [], bottomChildren, bottomSections = [], rightItems }) => {
110
+ const MobileNavbar = ({ logo, topChildren, topSections = [], bottomChildren, bottomSections = [], rightItems, rollable = true }) => {
111
111
  const [isHidden, setIsHidden] = useState(false);
112
112
  const [isUnrolled, setIsUnrolled] = useState(false);
113
113
  const navRef = useRef(null);
114
114
  useScrollBlockage({
115
- disableScroll: isUnrolled,
115
+ disableScroll: rollable,
116
116
  key: "mobile_nav"
117
117
  });
118
118
  useScrollDetection({
119
119
  onScrollUp: () => setIsHidden(false),
120
120
  onScrollDown: () => setIsHidden(true),
121
- isEnabled: !isUnrolled
121
+ isEnabled: !isUnrolled && rollable
122
122
  });
123
123
  const backDivHeight = !isHidden ? navRef.current?.clientHeight ?? 0 : 0;
124
124
  const isBurgerShowed = topSections.length + bottomSections.length > 0;
@@ -1 +1 @@
1
- {"version":3,"file":"MobileNavbar.mjs","names":["navVariants: Variants","isUnrolled"],"sources":["../../../../src/components/Navbar/MobileNavbar.tsx"],"sourcesContent":["'use client';\n\nimport { m, type Variants } from 'framer-motion';\nimport { type ReactElement, type ReactNode, useRef, useState } from 'react';\nimport { useScrollBlockage, useScrollDetection } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\nimport type { TabSelectorItemProps } from '../TabSelector';\nimport { Burger } from './Burger';\n\n/**\n * Props for the MobileNavbar component\n * @template T - The tab props type extending TabProps\n */\ntype MobileNavbarProps<T extends TabSelectorItemProps> = {\n /** Logo component or element displayed in the header */\n logo: ReactNode;\n /** Additional content displayed at the top of expanded mobile menu */\n topChildren?: ReactNode;\n /** Navigation sections displayed in the top area of expanded menu */\n topSections?: ReactElement<T>[];\n /** Additional content displayed at the bottom of expanded mobile menu */\n bottomChildren?: ReactNode;\n /** Navigation sections displayed in the bottom area of expanded menu */\n bottomSections?: ReactElement<T>[];\n /** Right-aligned items in the collapsed header (e.g., search, notifications) */\n rightItems?: ReactNode;\n};\n\n/**\n * Framer Motion animation variants for staggered menu item reveals\n * Creates a smooth cascading effect when menu opens/closes\n */\nconst navVariants: Variants = {\n open: {\n transition: { staggerChildren: 0.07, delayChildren: 0.2 },\n },\n closed: {\n transition: { staggerChildren: 0.05, staggerDirection: -1 },\n },\n};\n\n/**\n * Shared background styling for mobile navbar components\n * Provides glass-morphism effect with blur and transparency\n */\nconst bgStyle =\n 'bg-card/95 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blur';\n\n/**\n * Mobile Navigation Bar Component\n *\n * A sophisticated mobile-first navigation component with collapsible full-screen menu,\n * scroll-aware behavior, and smooth animations. Optimized for touch interactions and\n * mobile user experience patterns.\n *\n * Features:\n * - Collapsible hamburger menu with full-screen overlay\n * - Auto-hide on scroll down, show on scroll up for screen space optimization\n * - Background scroll prevention when menu is open\n * - Staggered animations for smooth menu item reveals\n * - Flexible content areas (top/bottom children and sections)\n * - Responsive layout with viewport-aware sizing\n * - Backdrop blur effects for modern glass-morphism design\n *\n * Layout Structure:\n * ```\n * [Logo] ----------- [Right Items] [Burger]\n * (when expanded)\n * ┌─────────────────────────────────────────┐\n * │ [Top Children] │\n * │ [Top Sections - Navigation Items] │\n * │ [Bottom Sections - Navigation Items] │\n * │ [Bottom Children] │\n * └─────────────────────────────────────────┘\n * ```\n *\n * Behavioral Features:\n * - Sticky positioning with dynamic hide/show based on scroll direction\n * - Background scroll locking when menu is expanded\n * - Click outside to close expanded menu\n * - Smooth height animations with MaxHeightSmoother\n * - Intelligent burger button visibility (only shown if sections exist)\n *\n * Animation Details:\n * - Menu items animate in with staggered timing (70ms delay between items)\n * - Exit animations are reversed with 50ms stagger\n * - Initial delay of 200ms before items start animating in\n * - Full viewport height menu with dynamic height calculation\n *\n * @example\n * Basic mobile navbar:\n * ```tsx\n * <MobileNavbar\n * logo={<MobileLogo />}\n * topSections={primaryNavItems}\n * rightItems={<SearchIcon />}\n * />\n * ```\n *\n * @example\n * Full-featured mobile navbar:\n * ```tsx\n * <MobileNavbar\n * logo={<Logo />}\n * topChildren={<WelcomeMessage />}\n * topSections={mainNavItems}\n * bottomSections={utilityNavItems}\n * bottomChildren={<UserProfile />}\n * rightItems={\n * <>\n * <NotificationIcon />\n * <SearchIcon />\n * </>\n * }\n * />\n * ```\n *\n * Accessibility Features:\n * - Menu expanded state communicated via aria-expanded\n * - Focus management and keyboard navigation support\n * - Screen reader friendly with semantic nav structure\n *\n * @template T - Tab properties type extending TabProps for type safety\n * @param props - MobileNavbar component props\n * @returns Mobile navigation with collapsible full-screen menu\n */\nexport const MobileNavbar = <T extends TabSelectorItemProps>({\n logo,\n topChildren,\n topSections = [],\n bottomChildren,\n bottomSections = [],\n rightItems,\n}: MobileNavbarProps<T>) => {\n const [isHidden, setIsHidden] = useState<boolean>(false);\n const [isUnrolled, setIsUnrolled] = useState<boolean>(false);\n\n const navRef = useRef<HTMLDivElement>(null);\n\n useScrollBlockage({\n disableScroll: isUnrolled,\n key: 'mobile_nav',\n });\n\n useScrollDetection({\n onScrollUp: () => setIsHidden(false),\n onScrollDown: () => setIsHidden(true),\n isEnabled: !isUnrolled,\n });\n\n const backDivHeight = !isHidden ? (navRef.current?.clientHeight ?? 0) : 0;\n\n const isBurgerShowed = topSections.length + bottomSections.length > 0;\n\n return (\n <nav\n className={cn(\n bgStyle,\n 'sticky top-0 z-50 flex w-screen flex-col transition',\n isHidden ? '-translate-y-full' : 'translate-y-0'\n )}\n id=\"mobile-menu\"\n >\n <div\n className=\"flex w-full items-center justify-between gap-1 px-4 py-3 md:gap-[10vw]\"\n ref={navRef}\n >\n {logo}\n\n <div className=\"flex w-full flex-1 items-center justify-end gap-6\">\n <div className=\"flex w-full items-center justify-end gap-1\">\n {rightItems}\n </div>\n\n {isBurgerShowed && (\n <Burger\n isActive={isUnrolled}\n onClick={() => setIsUnrolled((isUnrolled) => !isUnrolled)}\n />\n )}\n </div>\n </div>\n\n <div\n className={cn(\n bgStyle,\n 'absolute bottom-0 left-0 w-full translate-y-full'\n )}\n >\n <MaxHeightSmoother isHidden={!isUnrolled}>\n <m.div\n className=\"flex w-full flex-col pt-10 pb-[20%] text-lg text-text tracking-wide\"\n onClick={() => setIsUnrolled(false)}\n animate={isUnrolled ? 'open' : 'closed'}\n variants={navVariants}\n style={{\n height: `calc(100vh - ${backDivHeight}px)`,\n }}\n >\n {topChildren}\n <div className=\"flex h-full flex-col justify-center\">\n {topSections}\n {bottomSections}\n </div>\n\n <div className=\"m-auto flex w-full max-w-[400px] items-center justify-center gap-1 px-5 py-3\">\n {bottomChildren}\n </div>\n </m.div>\n </MaxHeightSmoother>\n </div>\n </nav>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAiCA,MAAMA,cAAwB;CAC5B,MAAM,EACJ,YAAY;EAAE,iBAAiB;EAAM,eAAe;EAAK,EAC1D;CACD,QAAQ,EACN,YAAY;EAAE,iBAAiB;EAAM,kBAAkB;EAAI,EAC5D;CACF;;;;;AAMD,MAAM,UACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFF,MAAa,gBAAgD,EAC3D,MACA,aACA,cAAc,EAAE,EAChB,gBACA,iBAAiB,EAAE,EACnB,iBAC0B;CAC1B,MAAM,CAAC,UAAU,eAAe,SAAkB,MAAM;CACxD,MAAM,CAAC,YAAY,iBAAiB,SAAkB,MAAM;CAE5D,MAAM,SAAS,OAAuB,KAAK;AAE3C,mBAAkB;EAChB,eAAe;EACf,KAAK;EACN,CAAC;AAEF,oBAAmB;EACjB,kBAAkB,YAAY,MAAM;EACpC,oBAAoB,YAAY,KAAK;EACrC,WAAW,CAAC;EACb,CAAC;CAEF,MAAM,gBAAgB,CAAC,WAAY,OAAO,SAAS,gBAAgB,IAAK;CAExE,MAAM,iBAAiB,YAAY,SAAS,eAAe,SAAS;AAEpE,QACE,qBAAC;EACC,WAAW,GACT,SACA,uDACA,WAAW,sBAAsB,gBAClC;EACD,IAAG;aAEH,qBAAC;GACC,WAAU;GACV,KAAK;cAEJ,MAED,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAI,WAAU;eACZ;MACG,EAEL,kBACC,oBAAC;KACC,UAAU;KACV,eAAe,eAAe,iBAAe,CAACC,aAAW;MACzD;KAEA;IACF,EAEN,oBAAC;GACC,WAAW,GACT,SACA,mDACD;aAED,oBAAC;IAAkB,UAAU,CAAC;cAC5B,qBAAC,EAAE;KACD,WAAU;KACV,eAAe,cAAc,MAAM;KACnC,SAAS,aAAa,SAAS;KAC/B,UAAU;KACV,OAAO,EACL,QAAQ,gBAAgB,cAAc,MACvC;;MAEA;MACD,qBAAC;OAAI,WAAU;kBACZ,aACA;QACG;MAEN,oBAAC;OAAI,WAAU;iBACZ;QACG;;MACA;KACU;IAChB;GACF"}
1
+ {"version":3,"file":"MobileNavbar.mjs","names":["navVariants: Variants","isUnrolled"],"sources":["../../../../src/components/Navbar/MobileNavbar.tsx"],"sourcesContent":["'use client';\n\nimport { m, type Variants } from 'framer-motion';\nimport { type ReactElement, type ReactNode, useRef, useState } from 'react';\nimport { useScrollBlockage, useScrollDetection } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\nimport type { TabSelectorItemProps } from '../TabSelector';\nimport { Burger } from './Burger';\n\n/**\n * Props for the MobileNavbar component\n * @template T - The tab props type extending TabProps\n */\ntype MobileNavbarProps<T extends TabSelectorItemProps> = {\n /** Logo component or element displayed in the header */\n logo: ReactNode;\n /** Additional content displayed at the top of expanded mobile menu */\n topChildren?: ReactNode;\n /** Navigation sections displayed in the top area of expanded menu */\n topSections?: ReactElement<T>[];\n /** Additional content displayed at the bottom of expanded mobile menu */\n bottomChildren?: ReactNode;\n /** Navigation sections displayed in the bottom area of expanded menu */\n bottomSections?: ReactElement<T>[];\n /** Right-aligned items in the collapsed header (e.g., search, notifications) */\n rightItems?: ReactNode;\n /** Whether the navbar should be rollable (default: true) */\n rollable?: boolean;\n};\n\n/**\n * Framer Motion animation variants for staggered menu item reveals\n * Creates a smooth cascading effect when menu opens/closes\n */\nconst navVariants: Variants = {\n open: {\n transition: { staggerChildren: 0.07, delayChildren: 0.2 },\n },\n closed: {\n transition: { staggerChildren: 0.05, staggerDirection: -1 },\n },\n};\n\n/**\n * Shared background styling for mobile navbar components\n * Provides glass-morphism effect with blur and transparency\n */\nconst bgStyle =\n 'bg-card/95 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blur';\n\n/**\n * Mobile Navigation Bar Component\n *\n * A sophisticated mobile-first navigation component with rollable full-screen menu,\n * scroll-aware behavior, and smooth animations. Optimized for touch interactions and\n * mobile user experience patterns.\n *\n * Features:\n * - rollable hamburger menu with full-screen overlay\n * - Auto-hide on scroll down, show on scroll up for screen space optimization\n * - Background scroll prevention when menu is open\n * - Staggered animations for smooth menu item reveals\n * - Flexible content areas (top/bottom children and sections)\n * - Responsive layout with viewport-aware sizing\n * - Backdrop blur effects for modern glass-morphism design\n *\n * Layout Structure:\n * ```\n * [Logo] ----------- [Right Items] [Burger]\n * (when expanded)\n * ┌─────────────────────────────────────────┐\n * │ [Top Children] │\n * │ [Top Sections - Navigation Items] │\n * │ [Bottom Sections - Navigation Items] │\n * │ [Bottom Children] │\n * └─────────────────────────────────────────┘\n * ```\n *\n * Behavioral Features:\n * - Sticky positioning with dynamic hide/show based on scroll direction\n * - Background scroll locking when menu is expanded\n * - Click outside to close expanded menu\n * - Smooth height animations with MaxHeightSmoother\n * - Intelligent burger button visibility (only shown if sections exist)\n *\n * Animation Details:\n * - Menu items animate in with staggered timing (70ms delay between items)\n * - Exit animations are reversed with 50ms stagger\n * - Initial delay of 200ms before items start animating in\n * - Full viewport height menu with dynamic height calculation\n *\n * @example\n * Basic mobile navbar:\n * ```tsx\n * <MobileNavbar\n * logo={<MobileLogo />}\n * topSections={primaryNavItems}\n * rightItems={<SearchIcon />}\n * />\n * ```\n *\n * @example\n * Full-featured mobile navbar:\n * ```tsx\n * <MobileNavbar\n * logo={<Logo />}\n * topChildren={<WelcomeMessage />}\n * topSections={mainNavItems}\n * bottomSections={utilityNavItems}\n * bottomChildren={<UserProfile />}\n * rightItems={\n * <>\n * <NotificationIcon />\n * <SearchIcon />\n * </>\n * }\n * />\n * ```\n *\n * Accessibility Features:\n * - Menu expanded state communicated via aria-expanded\n * - Focus management and keyboard navigation support\n * - Screen reader friendly with semantic nav structure\n *\n * @template T - Tab properties type extending TabProps for type safety\n * @param props - MobileNavbar component props\n * @returns Mobile navigation with rollable full-screen menu\n */\nexport const MobileNavbar = <T extends TabSelectorItemProps>({\n logo,\n topChildren,\n topSections = [],\n bottomChildren,\n bottomSections = [],\n rightItems,\n rollable = true,\n}: MobileNavbarProps<T>) => {\n const [isHidden, setIsHidden] = useState<boolean>(false);\n const [isUnrolled, setIsUnrolled] = useState<boolean>(false);\n\n const navRef = useRef<HTMLDivElement>(null);\n\n useScrollBlockage({\n disableScroll: rollable,\n key: 'mobile_nav',\n });\n\n useScrollDetection({\n onScrollUp: () => setIsHidden(false),\n onScrollDown: () => setIsHidden(true),\n isEnabled: !isUnrolled && rollable,\n });\n\n const backDivHeight = !isHidden ? (navRef.current?.clientHeight ?? 0) : 0;\n\n const isBurgerShowed = topSections.length + bottomSections.length > 0;\n\n return (\n <nav\n className={cn(\n bgStyle,\n 'sticky top-0 z-50 flex w-screen flex-col transition',\n isHidden ? '-translate-y-full' : 'translate-y-0'\n )}\n id=\"mobile-menu\"\n >\n <div\n className=\"flex w-full items-center justify-between gap-1 px-4 py-3 md:gap-[10vw]\"\n ref={navRef}\n >\n {logo}\n\n <div className=\"flex w-full flex-1 items-center justify-end gap-6\">\n <div className=\"flex w-full items-center justify-end gap-1\">\n {rightItems}\n </div>\n\n {isBurgerShowed && (\n <Burger\n isActive={isUnrolled}\n onClick={() => setIsUnrolled((isUnrolled) => !isUnrolled)}\n />\n )}\n </div>\n </div>\n\n <div\n className={cn(\n bgStyle,\n 'absolute bottom-0 left-0 w-full translate-y-full'\n )}\n >\n <MaxHeightSmoother isHidden={!isUnrolled}>\n <m.div\n className=\"flex w-full flex-col pt-10 pb-[20%] text-lg text-text tracking-wide\"\n onClick={() => setIsUnrolled(false)}\n animate={isUnrolled ? 'open' : 'closed'}\n variants={navVariants}\n style={{\n height: `calc(100vh - ${backDivHeight}px)`,\n }}\n >\n {topChildren}\n <div className=\"flex h-full flex-col justify-center\">\n {topSections}\n {bottomSections}\n </div>\n\n <div className=\"m-auto flex w-full max-w-[400px] items-center justify-center gap-1 px-5 py-3\">\n {bottomChildren}\n </div>\n </m.div>\n </MaxHeightSmoother>\n </div>\n </nav>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAmCA,MAAMA,cAAwB;CAC5B,MAAM,EACJ,YAAY;EAAE,iBAAiB;EAAM,eAAe;EAAK,EAC1D;CACD,QAAQ,EACN,YAAY;EAAE,iBAAiB;EAAM,kBAAkB;EAAI,EAC5D;CACF;;;;;AAMD,MAAM,UACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFF,MAAa,gBAAgD,EAC3D,MACA,aACA,cAAc,EAAE,EAChB,gBACA,iBAAiB,EAAE,EACnB,YACA,WAAW,WACe;CAC1B,MAAM,CAAC,UAAU,eAAe,SAAkB,MAAM;CACxD,MAAM,CAAC,YAAY,iBAAiB,SAAkB,MAAM;CAE5D,MAAM,SAAS,OAAuB,KAAK;AAE3C,mBAAkB;EAChB,eAAe;EACf,KAAK;EACN,CAAC;AAEF,oBAAmB;EACjB,kBAAkB,YAAY,MAAM;EACpC,oBAAoB,YAAY,KAAK;EACrC,WAAW,CAAC,cAAc;EAC3B,CAAC;CAEF,MAAM,gBAAgB,CAAC,WAAY,OAAO,SAAS,gBAAgB,IAAK;CAExE,MAAM,iBAAiB,YAAY,SAAS,eAAe,SAAS;AAEpE,QACE,qBAAC;EACC,WAAW,GACT,SACA,uDACA,WAAW,sBAAsB,gBAClC;EACD,IAAG;aAEH,qBAAC;GACC,WAAU;GACV,KAAK;cAEJ,MAED,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAI,WAAU;eACZ;MACG,EAEL,kBACC,oBAAC;KACC,UAAU;KACV,eAAe,eAAe,iBAAe,CAACC,aAAW;MACzD;KAEA;IACF,EAEN,oBAAC;GACC,WAAW,GACT,SACA,mDACD;aAED,oBAAC;IAAkB,UAAU,CAAC;cAC5B,qBAAC,EAAE;KACD,WAAU;KACV,eAAe,cAAc,MAAM;KACnC,SAAS,aAAa,SAAS;KAC/B,UAAU;KACV,OAAO,EACL,QAAQ,gBAAgB,cAAc,MACvC;;MAEA;MACD,qBAAC;OAAI,WAAU;kBACZ,aACA;QACG;MAEN,oBAAC;OAAI,WAAU;iBACZ;QACG;;MACA;KACU;IAChB;GACF"}
@@ -63,7 +63,7 @@ import { Fragment, jsx } from "react/jsx-runtime";
63
63
  * @param props - Navbar component props
64
64
  * @returns Responsive navbar JSX element
65
65
  */
66
- const Navbar = ({ logo, mobileTopChildren, desktopSections = [], mobileTopSections = [], mobileBottomChildren, mobileBottomSections = [], rightItemsDesktop, rightItemsMobile, selectedChoice }) => {
66
+ const Navbar = ({ logo, mobileTopChildren, desktopSections = [], mobileTopSections = [], mobileBottomChildren, mobileBottomSections = [], rightItemsDesktop, rightItemsMobile, selectedChoice, mobileRollable = true }) => {
67
67
  const { isMobile } = useDevice("lg");
68
68
  if (!useIsMounted()) return /* @__PURE__ */ jsx(Fragment, {});
69
69
  return isMobile ? /* @__PURE__ */ jsx(MobileNavbar, {
@@ -72,7 +72,8 @@ const Navbar = ({ logo, mobileTopChildren, desktopSections = [], mobileTopSectio
72
72
  bottomChildren: mobileBottomChildren,
73
73
  bottomSections: mobileBottomSections,
74
74
  logo,
75
- rightItems: rightItemsMobile
75
+ rightItems: rightItemsMobile,
76
+ rollable: mobileRollable
76
77
  }) : /* @__PURE__ */ jsx(DesktopNavbar, {
77
78
  sections: desktopSections,
78
79
  rightItems: rightItemsDesktop,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Navbar/index.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport { useDevice, useIsMounted } from '../../hooks';\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};\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}: 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 />\n ) : (\n <DesktopNavbar\n sections={desktopSections}\n rightItems={rightItemsDesktop}\n logo={logo}\n selectedChoice={selectedChoice}\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,MAAa,UAA0C,EACrD,MACA,mBACA,kBAAkB,EAAE,EACpB,oBAAoB,EAAE,EACtB,sBACA,uBAAuB,EAAE,EACzB,mBACA,kBACA,qBACoB;CACpB,MAAM,EAAE,aAAa,UAAU,KAAK;AAGpC,KAAI,CAFc,cAAc,CAEhB,QAAO,iCAAK;AAE5B,QAAO,WACL,oBAAC;EACC,aAAa;EACb,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EACV;EACN,YAAY;GACZ,GAEF,oBAAC;EACC,UAAU;EACV,YAAY;EACN;EACU;GAChB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Navbar/index.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport { useDevice, useIsMounted } from '../../hooks';\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,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,iCAAK;AAE5B,QAAO,WACL,oBAAC;EACC,aAAa;EACb,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EACV;EACN,YAAY;EACZ,UAAU;GACV,GAEF,oBAAC;EACC,UAAU;EACV,YAAY;EACN;EACU;GAChB"}
@@ -114,33 +114,59 @@ import { jsx } from "react/jsx-runtime";
114
114
  * - Graceful degradation for older browsers
115
115
  * - Mobile-first touch interaction handling
116
116
  */
117
- const WithResizer = ({ initialWidth, maxWidth, minWidth = 0, children }) => {
117
+ const WithResizer = ({ initialWidth, maxWidth, minWidth = 0, handlePosition = "right", children }) => {
118
118
  const containerRef = useRef(null);
119
119
  const [width, setWidth] = useState(initialWidth);
120
- const [isResizing, setIsResizing] = useState(false);
120
+ const resizeState = useRef({
121
+ startX: 0,
122
+ startWidth: 0,
123
+ factor: 1
124
+ });
125
+ const resize = useCallback((mouseMoveEvent) => {
126
+ if (resizeState.current.startWidth === 0) return;
127
+ let clientX = 0;
128
+ if (mouseMoveEvent instanceof MouseEvent) clientX = mouseMoveEvent.clientX;
129
+ else if (typeof TouchEvent !== "undefined" && mouseMoveEvent instanceof TouchEvent) clientX = mouseMoveEvent.touches[0].clientX;
130
+ const { startX, startWidth, factor } = resizeState.current;
131
+ const delta = (clientX - startX) / factor;
132
+ const newWidth = startWidth + (handlePosition === "left" ? -delta : delta);
133
+ setWidth(Math.max(Math.min(newWidth, maxWidth ?? Infinity), minWidth));
134
+ }, [
135
+ maxWidth,
136
+ minWidth,
137
+ handlePosition
138
+ ]);
139
+ const stopResizing = useCallback(() => {
140
+ document.body.style.cursor = "";
141
+ document.body.style.userSelect = "";
142
+ window.removeEventListener("mousemove", resize);
143
+ window.removeEventListener("mouseup", stopResizing);
144
+ window.removeEventListener("touchmove", resize);
145
+ window.removeEventListener("touchend", stopResizing);
146
+ }, [resize]);
121
147
  const startResizing = useCallback((mouseDownEvent) => {
122
- setIsResizing(true);
123
148
  mouseDownEvent.preventDefault();
124
- }, []);
125
- const stopResizing = useCallback(() => {
126
- setIsResizing(false);
127
- }, []);
128
- const resize = useCallback((mouseMoveEvent) => {
129
149
  const container = containerRef.current;
130
- if (isResizing && container && parent) {
131
- const { left: containerLeft } = container.getBoundingClientRect();
132
- let clientX = 0;
133
- if (mouseMoveEvent instanceof MouseEvent) clientX = mouseMoveEvent.clientX;
134
- else if (mouseMoveEvent instanceof TouchEvent) clientX = mouseMoveEvent.touches[0].clientX;
135
- const newWidth = clientX - containerLeft;
136
- setWidth(Math.max(newWidth, 0));
137
- }
138
- }, [isResizing]);
139
- useEffect(() => {
150
+ if (!container) return;
151
+ const { width: rectWidth } = container.getBoundingClientRect();
152
+ const offsetWidth = container.offsetWidth;
153
+ const factor = offsetWidth > 0 ? rectWidth / offsetWidth : 1;
154
+ let clientX = 0;
155
+ if ("touches" in mouseDownEvent) clientX = mouseDownEvent.touches[0].clientX;
156
+ else clientX = mouseDownEvent.clientX;
157
+ resizeState.current = {
158
+ startX: clientX,
159
+ startWidth: offsetWidth,
160
+ factor
161
+ };
162
+ document.body.style.cursor = "ew-resize";
163
+ document.body.style.userSelect = "none";
140
164
  window.addEventListener("mousemove", resize, { passive: true });
141
165
  window.addEventListener("mouseup", stopResizing);
142
166
  window.addEventListener("touchmove", resize, { passive: true });
143
167
  window.addEventListener("touchend", stopResizing);
168
+ }, [resize, stopResizing]);
169
+ useEffect(() => {
144
170
  return () => {
145
171
  window.removeEventListener("mousemove", resize);
146
172
  window.removeEventListener("mouseup", stopResizing);
@@ -149,7 +175,7 @@ const WithResizer = ({ initialWidth, maxWidth, minWidth = 0, children }) => {
149
175
  };
150
176
  }, [resize, stopResizing]);
151
177
  return /* @__PURE__ */ jsx("div", {
152
- className: cn(minWidth && `max-w-[${maxWidth}px]`, maxWidth && `min-w-[${minWidth}px]`, "relative h-full w-full max-w-[80%] cursor-ew-resize border-neutral-200 border-r-[2px] transition dark:border-neutral-950", "after:-translate-y-1/2 after:absolute after:top-1/2 after:right-0 after:block after:h-10 after:w-2 after:translate-x-1/2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950", "active:border-neutral-400 active:after:bg-neutral-400 dark:active:border-neutral-600 active:dark:after:bg-neutral-600"),
178
+ className: cn("relative h-full w-full max-w-[80%] shrink-0 cursor-ew-resize border-neutral-200 transition dark:border-neutral-950", handlePosition === "right" ? ["border-r-[2px]", "after:-translate-y-1/2 after:absolute after:top-1/2 after:right-0 after:block after:h-10 after:w-2 after:translate-x-1/2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950"] : ["border-l-[2px]", "after:-translate-y-1/2 after:-translate-x-1/2 after:absolute after:top-1/2 after:left-0 after:block after:h-10 after:w-2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950"], "active:border-neutral-400 active:after:bg-neutral-400 dark:active:border-neutral-600 active:dark:after:bg-neutral-600", minWidth && `min-w-[${minWidth}px]`, maxWidth && `max-w-[${maxWidth}px]`),
153
179
  style: { width: `${width}px` },
154
180
  ref: containerRef,
155
181
  onMouseDown: startResizing,
@@ -161,6 +187,7 @@ const WithResizer = ({ initialWidth, maxWidth, minWidth = 0, children }) => {
161
187
  role: "slider",
162
188
  tabIndex: 0,
163
189
  children: /* @__PURE__ */ jsx("div", {
190
+ role: "presentation",
164
191
  className: "absolute top-0 left-0 size-full cursor-default overflow-hidden",
165
192
  onMouseDown: (e) => e.stopPropagation(),
166
193
  onTouchStart: (e) => e.stopPropagation(),
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["WithResizer: FC<PropsWithChildren<WithResizerProps>>"],"sources":["../../../../src/components/WithResizer/index.tsx"],"sourcesContent":["'use client';\n\nimport React, {\n type FC,\n type PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for the WithResizer component.\n *\n * Defines the configuration for a resizable container with drag-based width adjustment.\n *\n * @example\n * ```tsx\n * // Basic resizable container\n * <WithResizer initialWidth={300} minWidth={200} maxWidth={600}>\n * <div className=\"p-4\">Resizable content</div>\n * </WithResizer>\n *\n * // Sidebar with resizing\n * <WithResizer\n * initialWidth={250}\n * minWidth={180}\n * maxWidth={400}\n * >\n * <nav className=\"h-full p-4\">\n * <SidebarContent />\n * </nav>\n * </WithResizer>\n *\n * // Panel with unlimited growth\n * <WithResizer initialWidth={400} minWidth={300}>\n * <div className=\"h-full overflow-auto\">\n * <PanelContent />\n * </div>\n * </WithResizer>\n * ```\n */\ntype WithResizerProps = {\n /** Initial width of the resizable container in pixels */\n initialWidth: number;\n /** Maximum allowed width in pixels (optional, no limit if not specified) */\n maxWidth?: number;\n /** Minimum allowed width in pixels */\n minWidth?: number;\n};\n\n/**\n * WithResizer Component\n *\n * A flexible container component that allows users to dynamically resize its width\n * through mouse or touch drag interactions. Perfect for creating adjustable panels,\n * sidebars, and split-pane layouts.\n *\n * ## Features\n * - **Mouse & Touch Support**: Works with both mouse drag and touch interactions\n * - **Constraint Enforcement**: Respects minimum and maximum width boundaries\n * - **Visual Feedback**: Clear resize handle with hover and active states\n * - **Smooth Interactions**: Passive event listeners for optimal performance\n * - **Accessibility**: ARIA slider role with proper value announcements\n * - **Responsive Design**: Adapts to different screen sizes and containers\n *\n * ## Technical Implementation\n * - **Event Handling**: Uses `useCallback` for optimal performance\n * - **Boundary Calculation**: Real-time width calculation based on mouse/touch position\n * - **State Management**: Tracks resizing state for visual feedback\n * - **Memory Management**: Proper cleanup of global event listeners\n * - **Touch Events**: Full support for mobile touch interactions\n *\n * ## Visual Design\n * - **Resize Handle**: Rounded handle positioned on the right border\n * - **Border Indicator**: Visual border showing resizable edge\n * - **State Feedback**: Different colors for normal, hover, and active states\n * - **Dark Mode**: Full support with appropriate color scheme\n * - **Smooth Transitions**: CSS transitions for visual polish\n *\n * ## Use Cases\n * - **Application Sidebars**: Collapsible navigation and tool panels\n * - **Content Panels**: Adjustable content areas in complex layouts\n * - **Split Panes**: Dividing screen space between multiple content areas\n * - **Inspector Panels**: Debugging tools and property inspectors\n * - **File Explorers**: Tree views with adjustable column widths\n * - **Dashboard Widgets**: Customizable widget sizes for dashboards\n *\n * ## Accessibility Features\n * - **ARIA Slider**: Proper slider role for screen readers\n * - **Value Announcements**: Current, minimum, and maximum values announced\n * - **Keyboard Focus**: Focusable with tab navigation\n * - **Clear Affordances**: Visual indicators for interactive elements\n *\n * @example\n * ```tsx\n * // Application sidebar with resizing\n * const [sidebarWidth, setSidebarWidth] = useState(250);\n *\n * <div className=\"flex h-screen\">\n * <WithResizer\n * initialWidth={sidebarWidth}\n * minWidth={200}\n * maxWidth={400}\n * >\n * <aside className=\"h-full bg-gray-100 p-4\">\n * <nav>\n * <NavItems />\n * </nav>\n * </aside>\n * </WithResizer>\n *\n * <main className=\"flex-1 p-6\">\n * <MainContent />\n * </main>\n * </div>\n *\n * // Developer tools panel\n * <WithResizer\n * initialWidth={350}\n * minWidth={250}\n * maxWidth={600}\n * >\n * <div className=\"h-full flex flex-col\">\n * <div className=\"flex-1 overflow-auto p-4\">\n * <InspectorContent />\n * </div>\n * <div className=\"border-t p-2\">\n * <Controls />\n * </div>\n * </div>\n * </WithResizer>\n *\n * // Multi-column layout\n * <div className=\"flex h-full\">\n * <WithResizer initialWidth={300} minWidth={200} maxWidth={500}>\n * <FileExplorer />\n * </WithResizer>\n *\n * <WithResizer initialWidth={400} minWidth={300}>\n * <CodeEditor />\n * </WithResizer>\n *\n * <div className=\"flex-1 min-w-0\">\n * <OutputPanel />\n * </div>\n * </div>\n * ```\n *\n * ## Performance Considerations\n * - Uses passive event listeners to prevent scroll blocking\n * - Optimized with `useCallback` to prevent unnecessary re-renders\n * - Efficient boundary calculations using `getBoundingClientRect`\n * - Minimal DOM manipulation for smooth drag interactions\n *\n * ## Browser Support\n * - Modern browsers with support for touch events\n * - Graceful degradation for older browsers\n * - Mobile-first touch interaction handling\n */\nexport const WithResizer: FC<PropsWithChildren<WithResizerProps>> = ({\n initialWidth,\n maxWidth,\n minWidth = 0,\n children,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(initialWidth);\n const [isResizing, setIsResizing] = useState(false);\n\n // Handler to start resizing\n const startResizing = useCallback(\n (\n mouseDownEvent:\n | React.MouseEvent<HTMLDivElement>\n | React.TouchEvent<HTMLDivElement>\n ) => {\n setIsResizing(true);\n mouseDownEvent.preventDefault();\n },\n []\n );\n\n // Handler to stop resizing\n const stopResizing = useCallback(() => {\n setIsResizing(false);\n }, []);\n\n // Handler to resize the div\n const resize = useCallback(\n (mouseMoveEvent: MouseEvent | TouchEvent) => {\n const container = containerRef.current;\n if (isResizing && container && parent) {\n const { left: containerLeft } = container.getBoundingClientRect();\n\n let clientX = 0;\n if (mouseMoveEvent instanceof MouseEvent) {\n clientX = mouseMoveEvent.clientX;\n } else if (mouseMoveEvent instanceof TouchEvent) {\n clientX = mouseMoveEvent.touches[0].clientX;\n }\n\n const newWidth = clientX - containerLeft;\n const correctedWidth = Math.max(newWidth, 0);\n\n setWidth(correctedWidth);\n }\n },\n [isResizing]\n );\n\n // Add event listeners for mouse move and mouse up\n useEffect(() => {\n window.addEventListener('mousemove', resize, { passive: true });\n window.addEventListener('mouseup', stopResizing);\n window.addEventListener('touchmove', resize, { passive: true });\n window.addEventListener('touchend', stopResizing);\n\n return () => {\n window.removeEventListener('mousemove', resize);\n window.removeEventListener('mouseup', stopResizing);\n window.removeEventListener('touchmove', resize);\n window.removeEventListener('touchend', stopResizing);\n };\n }, [resize, stopResizing]);\n\n return (\n <div\n className={cn(\n minWidth && `max-w-[${maxWidth}px]`,\n maxWidth && `min-w-[${minWidth}px]`,\n 'relative h-full w-full max-w-[80%] cursor-ew-resize border-neutral-200 border-r-[2px] transition dark:border-neutral-950',\n 'after:-translate-y-1/2 after:absolute after:top-1/2 after:right-0 after:block after:h-10 after:w-2 after:translate-x-1/2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950',\n 'active:border-neutral-400 active:after:bg-neutral-400 dark:active:border-neutral-600 active:dark:after:bg-neutral-600'\n )}\n style={{\n width: `${width}px`,\n }}\n ref={containerRef}\n onMouseDown={startResizing}\n onTouchStart={startResizing}\n aria-valuemin={minWidth}\n aria-valuemax={maxWidth}\n aria-valuenow={width}\n aria-label=\"Resizable component\"\n role=\"slider\"\n tabIndex={0}\n >\n <div\n className=\"absolute top-0 left-0 size-full cursor-default overflow-hidden\"\n onMouseDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n {children}\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiKA,MAAaA,eAAwD,EACnE,cACA,UACA,WAAW,GACX,eACI;CACJ,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,CAAC,OAAO,YAAY,SAAS,aAAa;CAChD,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CAGnD,MAAM,gBAAgB,aAElB,mBAGG;AACH,gBAAc,KAAK;AACnB,iBAAe,gBAAgB;IAEjC,EAAE,CACH;CAGD,MAAM,eAAe,kBAAkB;AACrC,gBAAc,MAAM;IACnB,EAAE,CAAC;CAGN,MAAM,SAAS,aACZ,mBAA4C;EAC3C,MAAM,YAAY,aAAa;AAC/B,MAAI,cAAc,aAAa,QAAQ;GACrC,MAAM,EAAE,MAAM,kBAAkB,UAAU,uBAAuB;GAEjE,IAAI,UAAU;AACd,OAAI,0BAA0B,WAC5B,WAAU,eAAe;YAChB,0BAA0B,WACnC,WAAU,eAAe,QAAQ,GAAG;GAGtC,MAAM,WAAW,UAAU;AAG3B,YAFuB,KAAK,IAAI,UAAU,EAAE,CAEpB;;IAG5B,CAAC,WAAW,CACb;AAGD,iBAAgB;AACd,SAAO,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAC;AAC/D,SAAO,iBAAiB,WAAW,aAAa;AAChD,SAAO,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAC;AAC/D,SAAO,iBAAiB,YAAY,aAAa;AAEjD,eAAa;AACX,UAAO,oBAAoB,aAAa,OAAO;AAC/C,UAAO,oBAAoB,WAAW,aAAa;AACnD,UAAO,oBAAoB,aAAa,OAAO;AAC/C,UAAO,oBAAoB,YAAY,aAAa;;IAErD,CAAC,QAAQ,aAAa,CAAC;AAE1B,QACE,oBAAC;EACC,WAAW,GACT,YAAY,UAAU,SAAS,MAC/B,YAAY,UAAU,SAAS,MAC/B,4HACA,2QACA,wHACD;EACD,OAAO,EACL,OAAO,GAAG,MAAM,KACjB;EACD,KAAK;EACL,aAAa;EACb,cAAc;EACd,iBAAe;EACf,iBAAe;EACf,iBAAe;EACf,cAAW;EACX,MAAK;EACL,UAAU;YAEV,oBAAC;GACC,WAAU;GACV,cAAc,MAAM,EAAE,iBAAiB;GACvC,eAAe,MAAM,EAAE,iBAAiB;GAEvC;IACG;GACF"}
1
+ {"version":3,"file":"index.mjs","names":["WithResizer: FC<PropsWithChildren<WithResizerProps>>"],"sources":["../../../../src/components/WithResizer/index.tsx"],"sourcesContent":["'use client';\n\nimport React, {\n type FC,\n type PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for the WithResizer component.\n *\n * Defines the configuration for a resizable container with drag-based width adjustment.\n *\n * @example\n * ```tsx\n * // Basic resizable container\n * <WithResizer initialWidth={300} minWidth={200} maxWidth={600}>\n * <div className=\"p-4\">Resizable content</div>\n * </WithResizer>\n *\n * // Sidebar with resizing\n * <WithResizer\n * initialWidth={250}\n * minWidth={180}\n * maxWidth={400}\n * >\n * <nav className=\"h-full p-4\">\n * <SidebarContent />\n * </nav>\n * </WithResizer>\n *\n * // Panel with unlimited growth\n * <WithResizer initialWidth={400} minWidth={300}>\n * <div className=\"h-full overflow-auto\">\n * <PanelContent />\n * </div>\n * </WithResizer>\n * ```\n */\ntype WithResizerProps = {\n /** Initial width of the resizable container in pixels */\n initialWidth: number;\n /** Maximum allowed width in pixels (optional, no limit if not specified) */\n maxWidth?: number;\n /** Minimum allowed width in pixels */\n minWidth?: number;\n /** Position of the resize handle (default: 'right') */\n handlePosition?: 'left' | 'right';\n};\n\n/**\n * WithResizer Component\n *\n * A flexible container component that allows users to dynamically resize its width\n * through mouse or touch drag interactions. Perfect for creating adjustable panels,\n * sidebars, and split-pane layouts.\n *\n * ## Features\n * - **Mouse & Touch Support**: Works with both mouse drag and touch interactions\n * - **Constraint Enforcement**: Respects minimum and maximum width boundaries\n * - **Visual Feedback**: Clear resize handle with hover and active states\n * - **Smooth Interactions**: Passive event listeners for optimal performance\n * - **Accessibility**: ARIA slider role with proper value announcements\n * - **Responsive Design**: Adapts to different screen sizes and containers\n *\n * ## Technical Implementation\n * - **Event Handling**: Uses `useCallback` for optimal performance\n * - **Boundary Calculation**: Real-time width calculation based on mouse/touch position\n * - **State Management**: Tracks resizing state for visual feedback\n * - **Memory Management**: Proper cleanup of global event listeners\n * - **Touch Events**: Full support for mobile touch interactions\n *\n * ## Visual Design\n * - **Resize Handle**: Rounded handle positioned on the right border\n * - **Border Indicator**: Visual border showing resizable edge\n * - **State Feedback**: Different colors for normal, hover, and active states\n * - **Dark Mode**: Full support with appropriate color scheme\n * - **Smooth Transitions**: CSS transitions for visual polish\n *\n * ## Use Cases\n * - **Application Sidebars**: Collapsible navigation and tool panels\n * - **Content Panels**: Adjustable content areas in complex layouts\n * - **Split Panes**: Dividing screen space between multiple content areas\n * - **Inspector Panels**: Debugging tools and property inspectors\n * - **File Explorers**: Tree views with adjustable column widths\n * - **Dashboard Widgets**: Customizable widget sizes for dashboards\n *\n * ## Accessibility Features\n * - **ARIA Slider**: Proper slider role for screen readers\n * - **Value Announcements**: Current, minimum, and maximum values announced\n * - **Keyboard Focus**: Focusable with tab navigation\n * - **Clear Affordances**: Visual indicators for interactive elements\n *\n * @example\n * ```tsx\n * // Application sidebar with resizing\n * const [sidebarWidth, setSidebarWidth] = useState(250);\n *\n * <div className=\"flex h-screen\">\n * <WithResizer\n * initialWidth={sidebarWidth}\n * minWidth={200}\n * maxWidth={400}\n * >\n * <aside className=\"h-full bg-gray-100 p-4\">\n * <nav>\n * <NavItems />\n * </nav>\n * </aside>\n * </WithResizer>\n *\n * <main className=\"flex-1 p-6\">\n * <MainContent />\n * </main>\n * </div>\n *\n * // Developer tools panel\n * <WithResizer\n * initialWidth={350}\n * minWidth={250}\n * maxWidth={600}\n * >\n * <div className=\"h-full flex flex-col\">\n * <div className=\"flex-1 overflow-auto p-4\">\n * <InspectorContent />\n * </div>\n * <div className=\"border-t p-2\">\n * <Controls />\n * </div>\n * </div>\n * </WithResizer>\n *\n * // Multi-column layout\n * <div className=\"flex h-full\">\n * <WithResizer initialWidth={300} minWidth={200} maxWidth={500}>\n * <FileExplorer />\n * </WithResizer>\n *\n * <WithResizer initialWidth={400} minWidth={300}>\n * <CodeEditor />\n * </WithResizer>\n *\n * <div className=\"flex-1 min-w-0\">\n * <OutputPanel />\n * </div>\n * </div>\n * ```\n *\n * ## Performance Considerations\n * - Uses passive event listeners to prevent scroll blocking\n * - Optimized with `useCallback` to prevent unnecessary re-renders\n * - Efficient boundary calculations using `getBoundingClientRect`\n * - Minimal DOM manipulation for smooth drag interactions\n *\n * ## Browser Support\n * - Modern browsers with support for touch events\n * - Graceful degradation for older browsers\n * - Mobile-first touch interaction handling\n */\nexport const WithResizer: FC<PropsWithChildren<WithResizerProps>> = ({\n initialWidth,\n maxWidth,\n minWidth = 0,\n handlePosition = 'right',\n children,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(initialWidth);\n\n const resizeState = useRef({\n startX: 0,\n startWidth: 0,\n factor: 1,\n });\n\n // Handler to resize the div\n const resize = useCallback(\n (mouseMoveEvent: MouseEvent | TouchEvent) => {\n if (resizeState.current.startWidth === 0) return;\n\n let clientX = 0;\n if (mouseMoveEvent instanceof MouseEvent) {\n clientX = mouseMoveEvent.clientX;\n } else if (\n typeof TouchEvent !== 'undefined' &&\n mouseMoveEvent instanceof TouchEvent\n ) {\n clientX = mouseMoveEvent.touches[0].clientX;\n }\n\n const { startX, startWidth, factor } = resizeState.current;\n const delta = (clientX - startX) / factor;\n // Invert delta for left handle (moving left decreases width, moving right increases width)\n const adjustedDelta = handlePosition === 'left' ? -delta : delta;\n const newWidth = startWidth + adjustedDelta;\n\n const constrainedWidth = Math.max(\n Math.min(newWidth, maxWidth ?? Infinity),\n minWidth\n );\n\n setWidth(constrainedWidth);\n },\n [maxWidth, minWidth, handlePosition]\n );\n\n // Handler to stop resizing\n const stopResizing = useCallback(() => {\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n window.removeEventListener('mousemove', resize);\n window.removeEventListener('mouseup', stopResizing);\n window.removeEventListener('touchmove', resize);\n window.removeEventListener('touchend', stopResizing);\n }, [resize]);\n\n // Handler to start resizing\n const startResizing = useCallback(\n (\n mouseDownEvent:\n | React.MouseEvent<HTMLDivElement>\n | React.TouchEvent<HTMLDivElement>\n ) => {\n mouseDownEvent.preventDefault();\n const container = containerRef.current;\n\n if (!container) return;\n\n const { width: rectWidth } = container.getBoundingClientRect();\n const offsetWidth = container.offsetWidth;\n const factor = offsetWidth > 0 ? rectWidth / offsetWidth : 1;\n\n let clientX = 0;\n if ('touches' in mouseDownEvent) {\n clientX = mouseDownEvent.touches[0].clientX;\n } else {\n clientX = mouseDownEvent.clientX;\n }\n\n resizeState.current = {\n startX: clientX,\n startWidth: offsetWidth,\n factor,\n };\n\n document.body.style.cursor = 'ew-resize';\n document.body.style.userSelect = 'none';\n\n window.addEventListener('mousemove', resize, { passive: true });\n window.addEventListener('mouseup', stopResizing);\n window.addEventListener('touchmove', resize, { passive: true });\n window.addEventListener('touchend', stopResizing);\n },\n [resize, stopResizing]\n );\n\n useEffect(() => {\n return () => {\n window.removeEventListener('mousemove', resize);\n window.removeEventListener('mouseup', stopResizing);\n window.removeEventListener('touchmove', resize);\n window.removeEventListener('touchend', stopResizing);\n };\n }, [resize, stopResizing]);\n\n return (\n <div\n className={cn(\n 'relative h-full w-full max-w-[80%] shrink-0 cursor-ew-resize border-neutral-200 transition dark:border-neutral-950',\n handlePosition === 'right'\n ? [\n 'border-r-[2px]',\n 'after:-translate-y-1/2 after:absolute after:top-1/2 after:right-0 after:block after:h-10 after:w-2 after:translate-x-1/2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950',\n ]\n : [\n 'border-l-[2px]',\n 'after:-translate-y-1/2 after:-translate-x-1/2 after:absolute after:top-1/2 after:left-0 after:block after:h-10 after:w-2 after:transform after:cursor-ew-resize after:rounded-full after:bg-neutral-200 after:transition after:content-[\"\"] dark:after:bg-neutral-950',\n ],\n 'active:border-neutral-400 active:after:bg-neutral-400 dark:active:border-neutral-600 active:dark:after:bg-neutral-600',\n minWidth && `min-w-[${minWidth}px]`,\n maxWidth && `max-w-[${maxWidth}px]`\n )}\n style={{\n width: `${width}px`,\n }}\n ref={containerRef}\n onMouseDown={startResizing}\n onTouchStart={startResizing}\n aria-valuemin={minWidth}\n aria-valuemax={maxWidth}\n aria-valuenow={width}\n aria-label=\"Resizable component\"\n role=\"slider\"\n tabIndex={0}\n >\n {/* biome-ignore lint/a11y/noStaticElementInteractions: This div stops event propagation to prevent content clicks from triggering resize */}\n <div\n role=\"presentation\"\n className=\"absolute top-0 left-0 size-full cursor-default overflow-hidden\"\n onMouseDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n {children}\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmKA,MAAaA,eAAwD,EACnE,cACA,UACA,WAAW,GACX,iBAAiB,SACjB,eACI;CACJ,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,CAAC,OAAO,YAAY,SAAS,aAAa;CAEhD,MAAM,cAAc,OAAO;EACzB,QAAQ;EACR,YAAY;EACZ,QAAQ;EACT,CAAC;CAGF,MAAM,SAAS,aACZ,mBAA4C;AAC3C,MAAI,YAAY,QAAQ,eAAe,EAAG;EAE1C,IAAI,UAAU;AACd,MAAI,0BAA0B,WAC5B,WAAU,eAAe;WAEzB,OAAO,eAAe,eACtB,0BAA0B,WAE1B,WAAU,eAAe,QAAQ,GAAG;EAGtC,MAAM,EAAE,QAAQ,YAAY,WAAW,YAAY;EACnD,MAAM,SAAS,UAAU,UAAU;EAGnC,MAAM,WAAW,cADK,mBAAmB,SAAS,CAAC,QAAQ;AAQ3D,WALyB,KAAK,IAC5B,KAAK,IAAI,UAAU,YAAY,SAAS,EACxC,SACD,CAEyB;IAE5B;EAAC;EAAU;EAAU;EAAe,CACrC;CAGD,MAAM,eAAe,kBAAkB;AACrC,WAAS,KAAK,MAAM,SAAS;AAC7B,WAAS,KAAK,MAAM,aAAa;AACjC,SAAO,oBAAoB,aAAa,OAAO;AAC/C,SAAO,oBAAoB,WAAW,aAAa;AACnD,SAAO,oBAAoB,aAAa,OAAO;AAC/C,SAAO,oBAAoB,YAAY,aAAa;IACnD,CAAC,OAAO,CAAC;CAGZ,MAAM,gBAAgB,aAElB,mBAGG;AACH,iBAAe,gBAAgB;EAC/B,MAAM,YAAY,aAAa;AAE/B,MAAI,CAAC,UAAW;EAEhB,MAAM,EAAE,OAAO,cAAc,UAAU,uBAAuB;EAC9D,MAAM,cAAc,UAAU;EAC9B,MAAM,SAAS,cAAc,IAAI,YAAY,cAAc;EAE3D,IAAI,UAAU;AACd,MAAI,aAAa,eACf,WAAU,eAAe,QAAQ,GAAG;MAEpC,WAAU,eAAe;AAG3B,cAAY,UAAU;GACpB,QAAQ;GACR,YAAY;GACZ;GACD;AAED,WAAS,KAAK,MAAM,SAAS;AAC7B,WAAS,KAAK,MAAM,aAAa;AAEjC,SAAO,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAC;AAC/D,SAAO,iBAAiB,WAAW,aAAa;AAChD,SAAO,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAC;AAC/D,SAAO,iBAAiB,YAAY,aAAa;IAEnD,CAAC,QAAQ,aAAa,CACvB;AAED,iBAAgB;AACd,eAAa;AACX,UAAO,oBAAoB,aAAa,OAAO;AAC/C,UAAO,oBAAoB,WAAW,aAAa;AACnD,UAAO,oBAAoB,aAAa,OAAO;AAC/C,UAAO,oBAAoB,YAAY,aAAa;;IAErD,CAAC,QAAQ,aAAa,CAAC;AAE1B,QACE,oBAAC;EACC,WAAW,GACT,sHACA,mBAAmB,UACf,CACE,kBACA,0QACD,GACD,CACE,kBACA,0QACD,EACL,yHACA,YAAY,UAAU,SAAS,MAC/B,YAAY,UAAU,SAAS,KAChC;EACD,OAAO,EACL,OAAO,GAAG,MAAM,KACjB;EACD,KAAK;EACL,aAAa;EACb,cAAc;EACd,iBAAe;EACf,iBAAe;EACf,iBAAe;EACf,cAAW;EACX,MAAK;EACL,UAAU;YAGV,oBAAC;GACC,MAAK;GACL,WAAU;GACV,cAAc,MAAM,EAAE,iBAAiB;GACvC,eAAe,MAAM,EAAE,iBAAiB;GAEvC;IACG;GACF"}
@@ -4,6 +4,7 @@ import { useAuth } from "./useAuth/useAuth.mjs";
4
4
  import { useIntlayerAuth, useIntlayerOAuth } from "./useIntlayerAPI.mjs";
5
5
  import { useAddDictionary, useAddNewAccessKey, useAddOrganization, useAddOrganizationMember, useAddPasskey, useAddProject, useAddTag, useAppQuery, useAskDocQuestion, useAskResetPassword, useAuditContentDeclaration, useAuditContentDeclarationField, useAuditContentDeclarationMetadata, useAuditTag, useAutocomplete, useCancelSubscription, useChangePassword, useCreateUser, useDeleteAccessKey, useDeleteDictionary, useDeleteOrganization, useDeletePasskey, useDeleteProject, useDeleteTag, useDeleteUser, useDisableTwoFactor, useEnableTwoFactor, useGetDictionaries, useGetDictionariesKeys, useGetDictionary, useGetDiscussions, useGetDiscussionsData, useGetEditorDictionaries, useGetNewsletterStatus, useGetOrganizations, useGetPricing, useGetProjects, useGetSubscription, useGetTags, useGetUserByAccount, useGetUserById, useGetUsers, useGetVerifyEmailStatus, useListPasskeys, useLogin, useLogout, usePushDictionaries, useQueryClient, useRefreshAccessKey, useRegister, useResetPassword, useSearchDoc, useSelectOrganization, useSelectProject, useSignInMagicLink, useSignInPasskey, useSubscribeToNewsletter, useTranslateJSONDeclaration, useUnselectOrganization, useUnselectProject, useUnsubscribeFromNewsletter, useUpdateDictionary, useUpdateOrganization, useUpdateOrganizationMembers, useUpdateOrganizationMembersById, useUpdateProject, useUpdateProjectMembers, useUpdateTag, useUpdateUser, useVerifyBackupCode, useVerifyEmail, useVerifyTotp, useWriteDictionary } from "./reactQuery.mjs";
6
6
  import { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice } from "./useDevice.mjs";
7
+ import { useGetElementById } from "./useGetElementById.mjs";
7
8
  import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
8
9
  import { useHorizontalSwipe } from "./useHorizontalSwipe.mjs";
9
10
  import { useIsDarkMode } from "./useIsDarkMode.mjs";
@@ -18,4 +19,4 @@ import { useScrollY } from "./useScrollY.mjs";
18
19
  import { useSearch } from "./useSearch.mjs";
19
20
  import { useUser } from "./useUser/index.mjs";
20
21
 
21
- export { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useAddDictionary, useAddNewAccessKey, useAddOrganization, useAddOrganizationMember, useAddPasskey, useAddProject, useAddTag, useAppQuery, useAskDocQuestion, useAskResetPassword, useAuditContentDeclaration, useAuditContentDeclarationField, useAuditContentDeclarationMetadata, useAuditTag, useAuth, useAutocomplete, useCancelSubscription, useChangePassword, useCreateUser, useDeleteAccessKey, useDeleteDictionary, useDeleteOrganization, useDeletePasskey, useDeleteProject, useDeleteTag, useDeleteUser, useDevice, useDisableTwoFactor, useEnableTwoFactor, useGetDictionaries, useGetDictionariesKeys, useGetDictionary, useGetDiscussions, useGetDiscussionsData, useGetEditorDictionaries, useGetElementOrWindow, useGetNewsletterStatus, useGetOrganizations, useGetPricing, useGetProjects, useGetSubscription, useGetTags, useGetUserByAccount, useGetUserById, useGetUsers, useGetVerifyEmailStatus, useHorizontalSwipe, useIntlayerAuth, useIntlayerOAuth, useIsDarkMode, useIsMounted, useItemSelector, useKeyboardDetector, useListPasskeys, useLogin, useLogout, useOAuth2, usePersistedStore, usePushDictionaries, useQueryClient, useRefreshAccessKey, useRegister, useResetPassword, useScreenWidth, useScrollBlockage, useScrollDetection, useScrollY, useSearch, useSearchDoc, useSelectOrganization, useSelectProject, useSession, useSignInMagicLink, useSignInPasskey, useSubscribeToNewsletter, useTranslateJSONDeclaration, useUnselectOrganization, useUnselectProject, useUnsubscribeFromNewsletter, useUpdateDictionary, useUpdateOrganization, useUpdateOrganizationMembers, useUpdateOrganizationMembersById, useUpdateProject, useUpdateProjectMembers, useUpdateTag, useUpdateUser, useUser, useVerifyBackupCode, useVerifyEmail, useVerifyTotp, useWriteDictionary };
22
+ export { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useAddDictionary, useAddNewAccessKey, useAddOrganization, useAddOrganizationMember, useAddPasskey, useAddProject, useAddTag, useAppQuery, useAskDocQuestion, useAskResetPassword, useAuditContentDeclaration, useAuditContentDeclarationField, useAuditContentDeclarationMetadata, useAuditTag, useAuth, useAutocomplete, useCancelSubscription, useChangePassword, useCreateUser, useDeleteAccessKey, useDeleteDictionary, useDeleteOrganization, useDeletePasskey, useDeleteProject, useDeleteTag, useDeleteUser, useDevice, useDisableTwoFactor, useEnableTwoFactor, useGetDictionaries, useGetDictionariesKeys, useGetDictionary, useGetDiscussions, useGetDiscussionsData, useGetEditorDictionaries, useGetElementById, useGetElementOrWindow, useGetNewsletterStatus, useGetOrganizations, useGetPricing, useGetProjects, useGetSubscription, useGetTags, useGetUserByAccount, useGetUserById, useGetUsers, useGetVerifyEmailStatus, useHorizontalSwipe, useIntlayerAuth, useIntlayerOAuth, useIsDarkMode, useIsMounted, useItemSelector, useKeyboardDetector, useListPasskeys, useLogin, useLogout, useOAuth2, usePersistedStore, usePushDictionaries, useQueryClient, useRefreshAccessKey, useRegister, useResetPassword, useScreenWidth, useScrollBlockage, useScrollDetection, useScrollY, useSearch, useSearchDoc, useSelectOrganization, useSelectProject, useSession, useSignInMagicLink, useSignInPasskey, useSubscribeToNewsletter, useTranslateJSONDeclaration, useUnselectOrganization, useUnselectProject, useUnsubscribeFromNewsletter, useUpdateDictionary, useUpdateOrganization, useUpdateOrganizationMembers, useUpdateOrganizationMembersById, useUpdateProject, useUpdateProjectMembers, useUpdateTag, useUpdateUser, useUser, useVerifyBackupCode, useVerifyEmail, useVerifyTotp, useWriteDictionary };
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ //#region src/hooks/useGetElementById.ts
6
+ const useGetElementById = (id) => {
7
+ const [element, setElement] = useState(void 0);
8
+ useEffect(() => {
9
+ setElement(document.getElementById(id));
10
+ }, [id]);
11
+ return element;
12
+ };
13
+
14
+ //#endregion
15
+ export { useGetElementById };
16
+ //# sourceMappingURL=useGetElementById.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGetElementById.mjs","names":[],"sources":["../../../src/hooks/useGetElementById.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\nexport const useGetElementById = (id: string) => {\n const [element, setElement] = useState<HTMLElement | undefined | null>(\n undefined\n );\n\n // This useEffect avoids the error of not finding the container\n useEffect(() => {\n setElement(document.getElementById(id));\n }, [id]);\n\n return element;\n};\n"],"mappings":";;;;;AAIA,MAAa,qBAAqB,OAAe;CAC/C,MAAM,CAAC,SAAS,cAAc,SAC5B,OACD;AAGD,iBAAgB;AACd,aAAW,SAAS,eAAe,GAAG,CAAC;IACtC,CAAC,GAAG,CAAC;AAER,QAAO"}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
3
4
  import { useCallback, useSyncExternalStore } from "react";
4
5
 
5
6
  //#region src/hooks/useScrollY.ts
@@ -9,9 +10,11 @@ const INITIAL_SCROLL_STATE = {
9
10
  scrollYMax: 0
10
11
  };
11
12
  let lastSnapshot = INITIAL_SCROLL_STATE;
12
- const useScrollY = () => {
13
+ const useScrollY = (props) => {
14
+ const { element } = props ?? {};
15
+ const containerElement = useGetElementOrWindow(element);
13
16
  const subscribe = useCallback((onChange) => {
14
- if (typeof window === "undefined") return () => {};
17
+ if (typeof window === "undefined" || !containerElement) return () => {};
15
18
  let raf = 0;
16
19
  const handler = () => {
17
20
  if (raf) return;
@@ -20,14 +23,28 @@ const useScrollY = () => {
20
23
  onChange();
21
24
  });
22
25
  };
23
- window.addEventListener("scroll", handler, { passive: true });
26
+ containerElement.addEventListener("scroll", handler, { passive: true });
24
27
  return () => {
25
- window.removeEventListener("scroll", handler);
28
+ containerElement.removeEventListener("scroll", handler);
26
29
  if (raf) window.cancelAnimationFrame(raf);
27
30
  };
28
- }, []);
31
+ }, [containerElement]);
29
32
  const getSnapshot = () => {
30
- if (typeof window === "undefined") return INITIAL_SCROLL_STATE;
33
+ if (typeof window === "undefined" || !containerElement) return INITIAL_SCROLL_STATE;
34
+ if (containerElement instanceof HTMLElement) {
35
+ const scrollY$1 = containerElement.scrollTop;
36
+ const scrollHeight$1 = containerElement.scrollHeight;
37
+ const clientHeight$1 = containerElement.clientHeight;
38
+ const scrollYMax$1 = Math.max(0, scrollHeight$1 - clientHeight$1);
39
+ const scrollPercentage$1 = scrollYMax$1 > 0 ? scrollY$1 / scrollYMax$1 : 0;
40
+ if (lastSnapshot.scrollY === scrollY$1 && lastSnapshot.scrollPercentage === scrollPercentage$1 && lastSnapshot.scrollYMax === scrollYMax$1) return lastSnapshot;
41
+ lastSnapshot = {
42
+ scrollY: scrollY$1,
43
+ scrollPercentage: scrollPercentage$1,
44
+ scrollYMax: scrollYMax$1
45
+ };
46
+ return lastSnapshot;
47
+ }
31
48
  const doc = document.documentElement;
32
49
  const body = document.body;
33
50
  const scrollY = window.scrollY ?? window.pageYOffset ?? doc?.scrollTop ?? body?.scrollTop ?? 0;
@@ -1 +1 @@
1
- {"version":3,"file":"useScrollY.mjs","names":["INITIAL_SCROLL_STATE: UseScrollYResult","lastSnapshot: UseScrollYResult"],"sources":["../../../src/hooks/useScrollY.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useSyncExternalStore } from 'react';\n\ntype UseScrollYResult = {\n scrollY: number;\n scrollPercentage: number;\n scrollYMax: number;\n};\n\nconst INITIAL_SCROLL_STATE: UseScrollYResult = {\n scrollY: 0,\n scrollPercentage: 0,\n scrollYMax: 0,\n};\n\nlet lastSnapshot: UseScrollYResult = INITIAL_SCROLL_STATE;\n\nexport const useScrollY = (): UseScrollYResult => {\n const subscribe = useCallback((onChange: () => void) => {\n if (typeof window === 'undefined') return () => {};\n let raf = 0;\n\n const handler = () => {\n if (raf) return;\n raf = window.requestAnimationFrame(() => {\n raf = 0;\n onChange();\n });\n };\n\n window.addEventListener('scroll', handler, { passive: true });\n\n return () => {\n window.removeEventListener('scroll', handler);\n if (raf) window.cancelAnimationFrame(raf);\n };\n }, []);\n\n const getSnapshot = (): UseScrollYResult => {\n if (typeof window === 'undefined') {\n return INITIAL_SCROLL_STATE; // SSR/hydration-safe\n }\n\n const doc = document.documentElement;\n const body = document.body;\n\n const scrollY =\n window.scrollY ??\n window.pageYOffset ??\n doc?.scrollTop ??\n body?.scrollTop ??\n 0;\n\n const scrollHeight = doc?.scrollHeight ?? body?.scrollHeight ?? 0;\n const clientHeight = doc?.clientHeight ?? window.innerHeight ?? 0;\n const scrollYMax = Math.max(0, scrollHeight - clientHeight);\n const scrollPercentage = scrollYMax > 0 ? scrollY / scrollYMax : 0;\n\n if (\n lastSnapshot.scrollY === scrollY &&\n lastSnapshot.scrollPercentage === scrollPercentage &&\n lastSnapshot.scrollYMax === scrollYMax\n ) {\n return lastSnapshot;\n }\n\n lastSnapshot = { scrollY, scrollPercentage, scrollYMax };\n return lastSnapshot;\n };\n\n const getServerSnapshot = (): UseScrollYResult => INITIAL_SCROLL_STATE;\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n};\n"],"mappings":";;;;;AAUA,MAAMA,uBAAyC;CAC7C,SAAS;CACT,kBAAkB;CAClB,YAAY;CACb;AAED,IAAIC,eAAiC;AAErC,MAAa,mBAAqC;CAChD,MAAM,YAAY,aAAa,aAAyB;AACtD,MAAI,OAAO,WAAW,YAAa,cAAa;EAChD,IAAI,MAAM;EAEV,MAAM,gBAAgB;AACpB,OAAI,IAAK;AACT,SAAM,OAAO,4BAA4B;AACvC,UAAM;AACN,cAAU;KACV;;AAGJ,SAAO,iBAAiB,UAAU,SAAS,EAAE,SAAS,MAAM,CAAC;AAE7D,eAAa;AACX,UAAO,oBAAoB,UAAU,QAAQ;AAC7C,OAAI,IAAK,QAAO,qBAAqB,IAAI;;IAE1C,EAAE,CAAC;CAEN,MAAM,oBAAsC;AAC1C,MAAI,OAAO,WAAW,YACpB,QAAO;EAGT,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,SAAS;EAEtB,MAAM,UACJ,OAAO,WACP,OAAO,eACP,KAAK,aACL,MAAM,aACN;EAEF,MAAM,eAAe,KAAK,gBAAgB,MAAM,gBAAgB;EAChE,MAAM,eAAe,KAAK,gBAAgB,OAAO,eAAe;EAChE,MAAM,aAAa,KAAK,IAAI,GAAG,eAAe,aAAa;EAC3D,MAAM,mBAAmB,aAAa,IAAI,UAAU,aAAa;AAEjE,MACE,aAAa,YAAY,WACzB,aAAa,qBAAqB,oBAClC,aAAa,eAAe,WAE5B,QAAO;AAGT,iBAAe;GAAE;GAAS;GAAkB;GAAY;AACxD,SAAO;;CAGT,MAAM,0BAA4C;AAElD,QAAO,qBAAqB,WAAW,aAAa,kBAAkB"}
1
+ {"version":3,"file":"useScrollY.mjs","names":["INITIAL_SCROLL_STATE: UseScrollYResult","lastSnapshot: UseScrollYResult","scrollY","scrollHeight","clientHeight","scrollYMax","scrollPercentage"],"sources":["../../../src/hooks/useScrollY.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useSyncExternalStore } from 'react';\nimport { useGetElementOrWindow } from './useGetElementOrWindow';\n\ntype UseScrollYProps = {\n element?: HTMLElement;\n};\n\ntype UseScrollYResult = {\n scrollY: number;\n scrollPercentage: number;\n scrollYMax: number;\n};\n\nconst INITIAL_SCROLL_STATE: UseScrollYResult = {\n scrollY: 0,\n scrollPercentage: 0,\n scrollYMax: 0,\n};\n\nlet lastSnapshot: UseScrollYResult = INITIAL_SCROLL_STATE;\n\nexport const useScrollY = (props?: UseScrollYProps): UseScrollYResult => {\n const { element } = props ?? {};\n\n const containerElement = useGetElementOrWindow(element);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n if (typeof window === 'undefined' || !containerElement) return () => {};\n let raf = 0;\n\n const handler = () => {\n if (raf) return;\n raf = window.requestAnimationFrame(() => {\n raf = 0;\n onChange();\n });\n };\n\n containerElement.addEventListener('scroll', handler, { passive: true });\n\n return () => {\n containerElement.removeEventListener('scroll', handler);\n if (raf) window.cancelAnimationFrame(raf);\n };\n },\n [containerElement]\n );\n\n const getSnapshot = (): UseScrollYResult => {\n if (typeof window === 'undefined' || !containerElement) {\n return INITIAL_SCROLL_STATE; // SSR/hydration-safe\n }\n\n // Handle custom element\n if (containerElement instanceof HTMLElement) {\n const scrollY = containerElement.scrollTop;\n const scrollHeight = containerElement.scrollHeight;\n const clientHeight = containerElement.clientHeight;\n const scrollYMax = Math.max(0, scrollHeight - clientHeight);\n const scrollPercentage = scrollYMax > 0 ? scrollY / scrollYMax : 0;\n\n if (\n lastSnapshot.scrollY === scrollY &&\n lastSnapshot.scrollPercentage === scrollPercentage &&\n lastSnapshot.scrollYMax === scrollYMax\n ) {\n return lastSnapshot;\n }\n\n lastSnapshot = { scrollY, scrollPercentage, scrollYMax };\n return lastSnapshot;\n }\n\n // Handle window\n const doc = document.documentElement;\n const body = document.body;\n\n const scrollY =\n window.scrollY ??\n window.pageYOffset ??\n doc?.scrollTop ??\n body?.scrollTop ??\n 0;\n\n const scrollHeight = doc?.scrollHeight ?? body?.scrollHeight ?? 0;\n const clientHeight = doc?.clientHeight ?? window.innerHeight ?? 0;\n const scrollYMax = Math.max(0, scrollHeight - clientHeight);\n const scrollPercentage = scrollYMax > 0 ? scrollY / scrollYMax : 0;\n\n if (\n lastSnapshot.scrollY === scrollY &&\n lastSnapshot.scrollPercentage === scrollPercentage &&\n lastSnapshot.scrollYMax === scrollYMax\n ) {\n return lastSnapshot;\n }\n\n lastSnapshot = { scrollY, scrollPercentage, scrollYMax };\n return lastSnapshot;\n };\n\n const getServerSnapshot = (): UseScrollYResult => INITIAL_SCROLL_STATE;\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n};\n"],"mappings":";;;;;;AAeA,MAAMA,uBAAyC;CAC7C,SAAS;CACT,kBAAkB;CAClB,YAAY;CACb;AAED,IAAIC,eAAiC;AAErC,MAAa,cAAc,UAA8C;CACvE,MAAM,EAAE,YAAY,SAAS,EAAE;CAE/B,MAAM,mBAAmB,sBAAsB,QAAQ;CAEvD,MAAM,YAAY,aACf,aAAyB;AACxB,MAAI,OAAO,WAAW,eAAe,CAAC,iBAAkB,cAAa;EACrE,IAAI,MAAM;EAEV,MAAM,gBAAgB;AACpB,OAAI,IAAK;AACT,SAAM,OAAO,4BAA4B;AACvC,UAAM;AACN,cAAU;KACV;;AAGJ,mBAAiB,iBAAiB,UAAU,SAAS,EAAE,SAAS,MAAM,CAAC;AAEvE,eAAa;AACX,oBAAiB,oBAAoB,UAAU,QAAQ;AACvD,OAAI,IAAK,QAAO,qBAAqB,IAAI;;IAG7C,CAAC,iBAAiB,CACnB;CAED,MAAM,oBAAsC;AAC1C,MAAI,OAAO,WAAW,eAAe,CAAC,iBACpC,QAAO;AAIT,MAAI,4BAA4B,aAAa;GAC3C,MAAMC,YAAU,iBAAiB;GACjC,MAAMC,iBAAe,iBAAiB;GACtC,MAAMC,iBAAe,iBAAiB;GACtC,MAAMC,eAAa,KAAK,IAAI,GAAGF,iBAAeC,eAAa;GAC3D,MAAME,qBAAmBD,eAAa,IAAIH,YAAUG,eAAa;AAEjE,OACE,aAAa,YAAYH,aACzB,aAAa,qBAAqBI,sBAClC,aAAa,eAAeD,aAE5B,QAAO;AAGT,kBAAe;IAAE;IAAS;IAAkB;IAAY;AACxD,UAAO;;EAIT,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,SAAS;EAEtB,MAAM,UACJ,OAAO,WACP,OAAO,eACP,KAAK,aACL,MAAM,aACN;EAEF,MAAM,eAAe,KAAK,gBAAgB,MAAM,gBAAgB;EAChE,MAAM,eAAe,KAAK,gBAAgB,OAAO,eAAe;EAChE,MAAM,aAAa,KAAK,IAAI,GAAG,eAAe,aAAa;EAC3D,MAAM,mBAAmB,aAAa,IAAI,UAAU,aAAa;AAEjE,MACE,aAAa,YAAY,WACzB,aAAa,qBAAqB,oBAClC,aAAa,eAAe,WAE5B,QAAO;AAGT,iBAAe;GAAE;GAAS;GAAkB;GAAY;AACxD,SAAO;;CAGT,MAAM,0BAA4C;AAElD,QAAO,qBAAqB,WAAW,aAAa,kBAAkB"}
@@ -1,5 +1,5 @@
1
1
  import { HTMLAttributes } from "react";
2
- import * as class_variance_authority_types14 from "class-variance-authority/types";
2
+ import * as class_variance_authority_types10 from "class-variance-authority/types";
3
3
  import { VariantProps } from "class-variance-authority";
4
4
 
5
5
  //#region src/components/Badge/index.d.ts
@@ -47,7 +47,7 @@ declare const badgeVariants: (props?: {
47
47
  color?: BadgeColor;
48
48
  variant?: BadgeVariant;
49
49
  size?: BadgeSize;
50
- } & class_variance_authority_types14.ClassProp) => string;
50
+ } & class_variance_authority_types10.ClassProp) => string;
51
51
  /**
52
52
  * Badge component props interface
53
53
  * @description Comprehensive props for the Badge component with accessibility and interactive features
@@ -1,10 +1,10 @@
1
- import * as _intlayer_types385 from "@intlayer/types";
1
+ import * as _intlayer_types0 from "@intlayer/types";
2
2
 
3
3
  //#region src/components/Breadcrumb/breadcrumb.content.d.ts
4
4
  declare const breadCrumbContent: {
5
5
  key: string;
6
6
  content: {
7
- linkLabel: _intlayer_types385.TypedNodeModel<_intlayer_types385.NodeType.Translation, {
7
+ linkLabel: _intlayer_types0.TypedNodeModel<_intlayer_types0.NodeType.Translation, {
8
8
  en: string;
9
9
  fr: string;
10
10
  es: string;
@@ -23,7 +23,7 @@ declare const breadCrumbContent: {
23
23
  id: string;
24
24
  vi: string;
25
25
  }, {
26
- nodeType: _intlayer_types385.NodeType.Translation | "translation";
26
+ nodeType: "translation" | _intlayer_types0.NodeType.Translation;
27
27
  } & {
28
28
  translation: {
29
29
  en: string;
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.content.d.ts","names":[],"sources":["../../../../src/components/Breadcrumb/breadcrumb.content.ts"],"sourcesContent":[],"mappings":";;;cAEa;;;IAAA,SAAA,mCA2BS,0CAAA"}
1
+ {"version":3,"file":"breadcrumb.content.d.ts","names":[],"sources":["../../../../src/components/Breadcrumb/breadcrumb.content.ts"],"sourcesContent":[],"mappings":";;;cAEa;;;IAAA,SAAA,iCA2BS,wCAAA"}
@@ -1,7 +1,7 @@
1
1
  import { LinkColor } from "../Link/Link.js";
2
2
  import "../Link/index.js";
3
3
  import { FC, HTMLAttributes, ReactNode } from "react";
4
- import * as class_variance_authority_types13 from "class-variance-authority/types";
4
+ import * as class_variance_authority_types0 from "class-variance-authority/types";
5
5
  import { VariantProps } from "class-variance-authority";
6
6
  import { LocalesValues } from "@intlayer/types";
7
7
 
@@ -12,7 +12,7 @@ import { LocalesValues } from "@intlayer/types";
12
12
  declare const breadcrumbVariants: (props?: {
13
13
  size?: "small" | "medium" | "large";
14
14
  spacing?: "compact" | "normal" | "loose";
15
- } & class_variance_authority_types13.ClassProp) => string;
15
+ } & class_variance_authority_types0.ClassProp) => string;
16
16
  /**
17
17
  * Detailed breadcrumb link configuration with optional href or onClick
18
18
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;cAqDM,0BA+JgC;EA/JhC,IAAA,CAAA,EAAA,OAAA,GAAA,QAiBJ,GAAA,OAAA;EA0HG,OAAA,CAAA,EAAA,SAAA,GAAA,QAAsB,GAAA,OAAA;AAoB3B,CAAA,GA9IE,gCAAA,CAAA,SA8IoC,EAAA,GAAsB,MAAA;AAE5D;;;KAtBK,sBAAA,GA+BoB;EAId;;;EAyBP,IAAA,CAAA,EAAA,MAAA;EACa;;;EA4BJ,IAAA,EAAA,MAAA;;;;;;;;;;;KArED,cAAA,YAA0B;KAE1B,eAAA;;;;SAIH;;;;;UAKC,eAAe;;;;WAId;;;;;;;;;;cAUG;;;;;;;;;;;;;;;IAeV,oBAAoB,sBACtB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BJ,YAAY,GAAG"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;cAqDM,0BA+JgC;EA/JhC,IAAA,CAAA,EAAA,OAAA,GAAA,QAiBJ,GAAA,OAAA;EA0HG,OAAA,CAAA,EAAA,SAAA,GAAA,QAAsB,GAAA,OAAA;AAoB3B,CAAA,GA9IE,+BAAA,CAAA,SA8IoC,EAAsB,GAAA,MAAA;AAE5D;;;KAtBK,sBAAA,GA+BoB;EAId;;;EAyBP,IAAA,CAAA,EAAA,MAAA;EACa;;;EA4BJ,IAAA,EAAA,MAAA;;;;;;;;;;;KArED,cAAA,YAA0B;KAE1B,eAAA;;;;SAIH;;;;;UAKC,eAAe;;;;WAId;;;;;;;;;;cAUG;;;;;;;;;;;;;;;IAeV,oBAAoB,sBACtB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BJ,YAAY,GAAG"}