@jbpark/ui-kit 3.7.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/Card.d.mts +1 -1
  2. package/dist/Card.d.mts.map +1 -1
  3. package/dist/Card.mjs.map +1 -1
  4. package/dist/Space.d.mts +1 -1
  5. package/dist/Space.d.mts.map +1 -1
  6. package/dist/Space.mjs.map +1 -1
  7. package/dist/components/atoms/checkbox/group.d.mts.map +1 -1
  8. package/dist/components/atoms/checkbox/group.mjs +4 -3
  9. package/dist/components/atoms/checkbox/group.mjs.map +1 -1
  10. package/dist/components/atoms/color-picker.d.mts +7 -1
  11. package/dist/components/atoms/color-picker.d.mts.map +1 -1
  12. package/dist/components/atoms/color-picker.mjs +8 -1
  13. package/dist/components/atoms/color-picker.mjs.map +1 -1
  14. package/dist/components/atoms/float-button/back-top.d.mts.map +1 -1
  15. package/dist/components/atoms/float-button/back-top.mjs +3 -1
  16. package/dist/components/atoms/float-button/back-top.mjs.map +1 -1
  17. package/dist/components/atoms/input/search.d.mts.map +1 -1
  18. package/dist/components/atoms/input/search.mjs +3 -1
  19. package/dist/components/atoms/input/search.mjs.map +1 -1
  20. package/dist/components/atoms/option-group.mjs +11 -1
  21. package/dist/components/atoms/option-group.mjs.map +1 -1
  22. package/dist/components/atoms/radio/group.d.mts.map +1 -1
  23. package/dist/components/atoms/radio/group.mjs +3 -2
  24. package/dist/components/atoms/radio/group.mjs.map +1 -1
  25. package/dist/components/atoms/skeleton/skeleton.d.mts.map +1 -1
  26. package/dist/components/atoms/skeleton/skeleton.mjs +5 -1
  27. package/dist/components/atoms/skeleton/skeleton.mjs.map +1 -1
  28. package/dist/components/atoms/spin.d.mts +2 -1
  29. package/dist/components/atoms/spin.d.mts.map +1 -1
  30. package/dist/components/atoms/spin.mjs +10 -4
  31. package/dist/components/atoms/spin.mjs.map +1 -1
  32. package/dist/components/molecules/collapse.d.mts +1 -1
  33. package/dist/components/molecules/collapse.d.mts.map +1 -1
  34. package/dist/components/molecules/collapse.mjs.map +1 -1
  35. package/dist/components/molecules/dropdown.d.mts +2 -2
  36. package/dist/components/molecules/dropdown.d.mts.map +1 -1
  37. package/dist/components/molecules/dropdown.mjs +25 -12
  38. package/dist/components/molecules/dropdown.mjs.map +1 -1
  39. package/dist/components/molecules/index.d.mts +9 -6
  40. package/dist/components/molecules/menu/item/item.mjs +27 -11
  41. package/dist/components/molecules/menu/item/item.mjs.map +1 -1
  42. package/dist/components/molecules/menu/menu.d.mts.map +1 -1
  43. package/dist/components/molecules/menu/menu.mjs +9 -7
  44. package/dist/components/molecules/menu/menu.mjs.map +1 -1
  45. package/dist/components/molecules/splitter/splitter.mjs +2 -2
  46. package/dist/components/molecules/splitter/splitter.mjs.map +1 -1
  47. package/dist/components/molecules/upload.d.mts +1 -1
  48. package/dist/components/organisms/drawer.d.mts.map +1 -1
  49. package/dist/components/organisms/drawer.mjs +3 -1
  50. package/dist/components/organisms/drawer.mjs.map +1 -1
  51. package/dist/components/organisms/imperative-stack.mjs +106 -0
  52. package/dist/components/organisms/imperative-stack.mjs.map +1 -0
  53. package/dist/components/organisms/index.d.mts +3 -1
  54. package/dist/components/organisms/list/index.d.mts +1 -1
  55. package/dist/components/organisms/list/index.mjs.map +1 -1
  56. package/dist/components/organisms/list/list.d.mts +2 -2
  57. package/dist/components/organisms/list/list.d.mts.map +1 -1
  58. package/dist/components/organisms/list/list.mjs +20 -11
  59. package/dist/components/organisms/list/list.mjs.map +1 -1
  60. package/dist/components/organisms/modal.d.mts +2 -2
  61. package/dist/components/organisms/modal.d.mts.map +1 -1
  62. package/dist/components/organisms/modal.mjs +21 -101
  63. package/dist/components/organisms/modal.mjs.map +1 -1
  64. package/dist/components/organisms/swiper/index.d.mts +1 -1
  65. package/dist/components/organisms/swiper/index.mjs.map +1 -1
  66. package/dist/components/organisms/swiper/swiper.d.mts +2 -1
  67. package/dist/components/organisms/swiper/swiper.d.mts.map +1 -1
  68. package/dist/components/organisms/swiper/swiper.mjs +5 -3
  69. package/dist/components/organisms/swiper/swiper.mjs.map +1 -1
  70. package/dist/components/organisms/toast.d.mts +1 -1
  71. package/dist/components/organisms/toast.d.mts.map +1 -1
  72. package/dist/components/organisms/toast.mjs +35 -111
  73. package/dist/components/organisms/toast.mjs.map +1 -1
  74. package/dist/components/templates/container.d.mts +19 -0
  75. package/dist/components/templates/container.d.mts.map +1 -0
  76. package/dist/components/templates/container.mjs +32 -0
  77. package/dist/components/templates/container.mjs.map +1 -0
  78. package/dist/components/templates/empty.d.mts +20 -0
  79. package/dist/components/templates/empty.d.mts.map +1 -0
  80. package/dist/components/templates/empty.mjs +34 -0
  81. package/dist/components/templates/empty.mjs.map +1 -0
  82. package/dist/components/templates/grid/col.d.mts +35 -0
  83. package/dist/components/templates/grid/col.d.mts.map +1 -0
  84. package/dist/components/templates/grid/col.mjs +55 -0
  85. package/dist/components/templates/grid/col.mjs.map +1 -0
  86. package/dist/components/templates/grid/index.d.mts +2 -0
  87. package/dist/components/templates/grid/row-context.mjs +13 -0
  88. package/dist/components/templates/grid/row-context.mjs.map +1 -0
  89. package/dist/components/templates/grid/row.d.mts +36 -0
  90. package/dist/components/templates/grid/row.d.mts.map +1 -0
  91. package/dist/components/templates/grid/row.mjs +54 -0
  92. package/dist/components/templates/grid/row.mjs.map +1 -0
  93. package/dist/components/templates/index.d.mts +13 -1
  94. package/dist/components/templates/layout/content.d.mts +4 -1
  95. package/dist/components/templates/layout/content.d.mts.map +1 -1
  96. package/dist/components/templates/layout/content.mjs +3 -2
  97. package/dist/components/templates/layout/content.mjs.map +1 -1
  98. package/dist/components/templates/layout/footer.d.mts +1 -1
  99. package/dist/components/templates/layout/footer.d.mts.map +1 -1
  100. package/dist/components/templates/layout/footer.mjs.map +1 -1
  101. package/dist/components/templates/layout/header.d.mts +4 -1
  102. package/dist/components/templates/layout/header.d.mts.map +1 -1
  103. package/dist/components/templates/layout/header.mjs +2 -2
  104. package/dist/components/templates/layout/header.mjs.map +1 -1
  105. package/dist/components/templates/layout/layout.d.mts +1 -1
  106. package/dist/components/templates/layout/layout.d.mts.map +1 -1
  107. package/dist/components/templates/layout/layout.mjs.map +1 -1
  108. package/dist/components/templates/layout/sider.d.mts +9 -2
  109. package/dist/components/templates/layout/sider.d.mts.map +1 -1
  110. package/dist/components/templates/layout/sider.mjs +40 -13
  111. package/dist/components/templates/layout/sider.mjs.map +1 -1
  112. package/dist/components/templates/page-header.d.mts +30 -0
  113. package/dist/components/templates/page-header.d.mts.map +1 -0
  114. package/dist/components/templates/page-header.mjs +45 -0
  115. package/dist/components/templates/page-header.mjs.map +1 -0
  116. package/dist/components/templates/result.d.mts +24 -0
  117. package/dist/components/templates/result.d.mts.map +1 -0
  118. package/dist/components/templates/result.mjs +46 -0
  119. package/dist/components/templates/result.mjs.map +1 -0
  120. package/dist/index.d.mts +29 -13
  121. package/dist/index.mjs +9 -3
  122. package/dist/providers/Config/context.d.mts +3 -2
  123. package/dist/providers/Config/context.d.mts.map +1 -1
  124. package/dist/providers/Config/context.mjs +13 -2
  125. package/dist/providers/Config/context.mjs.map +1 -1
  126. package/dist/providers/Config/index.d.mts +4 -2
  127. package/dist/providers/Config/index.d.mts.map +1 -1
  128. package/dist/providers/Config/index.mjs +14 -4
  129. package/dist/providers/Config/index.mjs.map +1 -1
  130. package/dist/providers/Config/types.d.mts +10 -1
  131. package/dist/providers/Config/types.d.mts.map +1 -1
  132. package/dist/providers.d.mts +4 -0
  133. package/dist/providers.mjs +4 -0
  134. package/dist/style.css +114 -3
  135. package/package.json +4 -3
  136. package/dist/providers/index.d.mts +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.d.mts","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"mappings":";;;;;KAUK,kBAAA,IAAsB,IAAA;AAAA,UAEjB,KAAA,SAAc,KAAA,CAAM,wBAAA;EAC5B,IAAA;EACA,OAAA;EACA,IAAA,GAAO,SAAA;EACP,YAAA,GAAe,kBAAA;AAAA;AAAA,cAGX,QAAA;EAAY,QAAA;EAAA,IAAA;EAAA,OAAA;EAAA,IAAA,EAAA,KAAA;EAAA,YAAA,EAAA,aAAA;EAAA,SAAA;EAAA,YAAA;EAAA,YAAA;EAAA,GAAA;AAAA,GAUf,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"dropdown.d.mts","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"mappings":";;;;;KAWK,kBAAA,IAAsB,IAAA;AAAA,UAEV,KAAA,SAAc,KAAA,CAAM,wBAAA;EACnC,IAAA;EACA,OAAA;EACA,IAAA,GAAO,SAAA;EACP,YAAA,GAAe,kBAAA;AAAA;AAAA,cAGX,QAAA;EAAY,QAAA;EAAA,IAAA;EAAA,OAAA;EAAA,IAAA,EAAA,KAAA;EAAA,YAAA,EAAA,aAAA;EAAA,SAAA;EAAA,YAAA;EAAA,YAAA;EAAA,GAAA;AAAA,GAUf,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -2,23 +2,25 @@
2
2
 
3
3
  import { cn } from "../../utils.mjs";
4
4
  import Menu from "./menu/menu.mjs";
5
- import { useState } from "react";
5
+ import { useId, useRef } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { useControllableState } from "@jbpark/use-hooks";
7
8
  import { AnimatePresence, motion } from "motion/react";
8
9
 
9
10
  //#region src/components/molecules/dropdown.tsx
10
11
  const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange: _onOpenChange = () => {}, className, onMouseEnter, onMouseLeave, ...props }) => {
11
- const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
12
- const controlled = _open !== void 0;
13
- const open = controlled ? _open : uncontrolledOpen;
12
+ const [open, onOpenChange] = useControllableState({
13
+ value: _open,
14
+ defaultValue: false,
15
+ onChange: _onOpenChange
16
+ });
14
17
  const isClickTrigger = trigger === "click";
15
- const onOpenChange = (nextOpen) => {
16
- if (!controlled) setUncontrolledOpen(nextOpen);
17
- _onOpenChange(nextOpen);
18
- };
18
+ const menuId = useId();
19
+ const containerRef = useRef(null);
19
20
  return /* @__PURE__ */ jsxs("div", {
20
21
  ...props,
21
- className: cn("relative z-0", "inline-block cursor-pointer", className),
22
+ ref: containerRef,
23
+ className: cn("relative", "inline-block cursor-pointer", className),
22
24
  onMouseEnter: (event) => {
23
25
  onMouseEnter?.(event);
24
26
  if (isClickTrigger) return;
@@ -30,8 +32,11 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
30
32
  onOpenChange(false);
31
33
  },
32
34
  children: [/* @__PURE__ */ jsx("div", {
35
+ role: isClickTrigger ? "button" : void 0,
36
+ tabIndex: isClickTrigger ? 0 : void 0,
33
37
  "aria-haspopup": "menu",
34
38
  "aria-expanded": open,
39
+ "aria-controls": open ? menuId : void 0,
35
40
  onClick: () => {
36
41
  if (!isClickTrigger) return;
37
42
  onOpenChange(!open);
@@ -40,11 +45,18 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
40
45
  if (isClickTrigger) return;
41
46
  onOpenChange(true);
42
47
  },
43
- onBlur: () => {
44
- onOpenChange(false);
48
+ onBlur: (e) => {
49
+ if (!containerRef.current?.contains(e.relatedTarget)) onOpenChange(false);
45
50
  },
46
51
  onKeyDown: (e) => {
47
- if (e.key === "Escape") onOpenChange(false);
52
+ if (e.key === "Escape") {
53
+ onOpenChange(false);
54
+ return;
55
+ }
56
+ if (isClickTrigger && (e.key === "Enter" || e.key === " ")) {
57
+ e.preventDefault();
58
+ onOpenChange(!open);
59
+ }
48
60
  },
49
61
  children
50
62
  }), /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(motion.div, {
@@ -64,6 +76,7 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
64
76
  transition: { duration: .1 },
65
77
  children: /* @__PURE__ */ jsx(Menu, {
66
78
  ...menu,
79
+ id: menuId,
67
80
  onMouseDown: (e) => {
68
81
  e.preventDefault();
69
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Menu, { MenuProps } from './menu';\n\ntype ChangeEventHandler = (open: boolean) => void;\n\ninterface Props extends React.ComponentPropsWithoutRef<'div'> {\n open?: boolean;\n trigger?: string;\n menu?: MenuProps;\n onOpenChange?: ChangeEventHandler;\n}\n\nconst Dropdown = ({\n children,\n menu,\n trigger = 'hover',\n open: _open,\n onOpenChange: _onOpenChange = () => {},\n className,\n onMouseEnter,\n onMouseLeave,\n ...props\n}: Props) => {\n const [uncontrolledOpen, setUncontrolledOpen] = useState<boolean>(false);\n\n const controlled = _open !== undefined;\n const open = controlled ? _open : uncontrolledOpen;\n\n const isClickTrigger = trigger === 'click';\n\n const onOpenChange = (nextOpen: boolean) => {\n if (!controlled) {\n setUncontrolledOpen(nextOpen);\n }\n _onOpenChange(nextOpen);\n };\n\n return (\n <div\n {...props}\n className={cn(\n 'relative z-0',\n 'inline-block cursor-pointer',\n className,\n //\n )}\n onMouseEnter={event => {\n onMouseEnter?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onMouseLeave={event => {\n onMouseLeave?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(false);\n }}\n >\n <div\n aria-haspopup=\"menu\"\n aria-expanded={open}\n onClick={() => {\n if (!isClickTrigger) {\n return;\n }\n onOpenChange(!open);\n }}\n onFocus={() => {\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onBlur={() => {\n onOpenChange(false);\n }}\n onKeyDown={e => {\n if (e.key === 'Escape') {\n onOpenChange(false);\n }\n }}\n >\n {children}\n </div>\n <AnimatePresence>\n {open && (\n <motion.div\n className={cn(\n 'absolute top-full pt-2',\n //\n )}\n initial={{ opacity: 0, y: -10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -10 }}\n transition={{ duration: 0.1 }}\n >\n <Menu\n {...menu}\n onMouseDown={e => {\n e.preventDefault();\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n\nexport default Dropdown;\n"],"mappings":";;;;;;;;;AAmBA,MAAM,YAAY,EAChB,UACA,MACA,UAAU,SACV,MAAM,OACN,cAAc,sBAAsB,IACpC,WACA,cACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,kBAAkB,uBAAuB,SAAkB,MAAM;CAExE,MAAM,aAAa,UAAU;CAC7B,MAAM,OAAO,aAAa,QAAQ;CAElC,MAAM,iBAAiB,YAAY;CAEnC,MAAM,gBAAgB,aAAsB;AAC1C,MAAI,CAAC,WACH,qBAAoB,SAAS;AAE/B,gBAAc,SAAS;;AAGzB,QACE,qBAAC;EACC,GAAI;EACJ,WAAW,GACT,gBACA,+BACA,UAED;EACD,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,KAAK;;EAEpB,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,MAAM;;aAGrB,oBAAC;GACC,iBAAc;GACd,iBAAe;GACf,eAAe;AACb,QAAI,CAAC,eACH;AAEF,iBAAa,CAAC,KAAK;;GAErB,eAAe;AACb,QAAI,eACF;AAEF,iBAAa,KAAK;;GAEpB,cAAc;AACZ,iBAAa,MAAM;;GAErB,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,SACZ,cAAa,MAAM;;GAItB;IACG,EACN,oBAAC,6BACE,QACC,oBAAC,OAAO;GACN,WAAW,GACT,yBAED;GACD,SAAS;IAAE,SAAS;IAAG,GAAG;IAAK;GAC/B,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,MAAM;IAAE,SAAS;IAAG,GAAG;IAAK;GAC5B,YAAY,EAAE,UAAU,IAAK;aAE7B,oBAAC;IACC,GAAI;IACJ,cAAa,MAAK;AAChB,OAAE,gBAAgB;;KAEpB;IACS,GAEC;GACd"}
1
+ {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Menu, { MenuProps } from './menu';\n\ntype ChangeEventHandler = (open: boolean) => void;\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n open?: boolean;\n trigger?: 'hover' | 'click';\n menu?: MenuProps;\n onOpenChange?: ChangeEventHandler;\n}\n\nconst Dropdown = ({\n children,\n menu,\n trigger = 'hover',\n open: _open,\n onOpenChange: _onOpenChange = () => {},\n className,\n onMouseEnter,\n onMouseLeave,\n ...props\n}: Props) => {\n const [open, onOpenChange] = useControllableState<boolean>({\n value: _open,\n defaultValue: false,\n onChange: _onOpenChange,\n });\n\n const isClickTrigger = trigger === 'click';\n const menuId = useId();\n const containerRef = useRef<HTMLDivElement>(null);\n\n return (\n <div\n {...props}\n ref={containerRef}\n className={cn(\n 'relative',\n 'inline-block cursor-pointer',\n className,\n //\n )}\n onMouseEnter={event => {\n onMouseEnter?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onMouseLeave={event => {\n onMouseLeave?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(false);\n }}\n >\n <div\n role={isClickTrigger ? 'button' : undefined}\n tabIndex={isClickTrigger ? 0 : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n onClick={() => {\n if (!isClickTrigger) {\n return;\n }\n onOpenChange(!open);\n }}\n onFocus={() => {\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onBlur={e => {\n // Without this check, moving focus from the trigger into the\n // menu itself (e.g. via Tab) closed the dropdown before the\n // user could ever reach it — the mouse path avoided the same\n // bug only by way of onMouseDown's preventDefault below, which\n // does nothing for keyboard focus. Mirrors the containment\n // check menu/item/item.tsx already uses for the same reason.\n if (!containerRef.current?.contains(e.relatedTarget as Node)) {\n onOpenChange(false);\n }\n }}\n onKeyDown={e => {\n if (e.key === 'Escape') {\n onOpenChange(false);\n return;\n }\n if (isClickTrigger && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onOpenChange(!open);\n }\n }}\n >\n {children}\n </div>\n <AnimatePresence>\n {open && (\n <motion.div\n className={cn(\n 'absolute top-full pt-2',\n //\n )}\n initial={{ opacity: 0, y: -10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -10 }}\n transition={{ duration: 0.1 }}\n >\n <Menu\n {...menu}\n id={menuId}\n onMouseDown={e => {\n e.preventDefault();\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n\nexport default Dropdown;\n"],"mappings":";;;;;;;;;;AAoBA,MAAM,YAAY,EAChB,UACA,MACA,UAAU,SACV,MAAM,OACN,cAAc,sBAAsB,IACpC,WACA,cACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,gBAAgB,qBAA8B;EACzD,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;CAEF,MAAM,iBAAiB,YAAY;CACnC,MAAM,SAAS,OAAO;CACtB,MAAM,eAAe,OAAuB,KAAK;AAEjD,QACE,qBAAC;EACC,GAAI;EACJ,KAAK;EACL,WAAW,GACT,YACA,+BACA,UAED;EACD,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,KAAK;;EAEpB,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,MAAM;;aAGrB,oBAAC;GACC,MAAM,iBAAiB,WAAW;GAClC,UAAU,iBAAiB,IAAI;GAC/B,iBAAc;GACd,iBAAe;GACf,iBAAe,OAAO,SAAS;GAC/B,eAAe;AACb,QAAI,CAAC,eACH;AAEF,iBAAa,CAAC,KAAK;;GAErB,eAAe;AACb,QAAI,eACF;AAEF,iBAAa,KAAK;;GAEpB,SAAQ,MAAK;AAOX,QAAI,CAAC,aAAa,SAAS,SAAS,EAAE,cAAsB,CAC1D,cAAa,MAAM;;GAGvB,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,UAAU;AACtB,kBAAa,MAAM;AACnB;;AAEF,QAAI,mBAAmB,EAAE,QAAQ,WAAW,EAAE,QAAQ,MAAM;AAC1D,OAAE,gBAAgB;AAClB,kBAAa,CAAC,KAAK;;;GAItB;IACG,EACN,oBAAC,6BACE,QACC,oBAAC,OAAO;GACN,WAAW,GACT,yBAED;GACD,SAAS;IAAE,SAAS;IAAG,GAAG;IAAK;GAC/B,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,MAAM;IAAE,SAAS;IAAG,GAAG;IAAK;GAC5B,YAAY,EAAE,UAAU,IAAK;aAE7B,oBAAC;IACC,GAAI;IACJ,IAAI;IACJ,cAAa,MAAK;AAChB,OAAE,gBAAgB;;KAEpB;IACS,GAEC;GACd"}
@@ -1,10 +1,13 @@
1
- import Card from "../../Card.mjs";
2
- import { Menu } from "./menu/menu.mjs";
1
+ import Card, { Props } from "../../Card.mjs";
2
+ import { Menu, Props as Props$1 } from "./menu/menu.mjs";
3
3
  import "../../Menu.mjs";
4
+ import { Props as Props$2 } from "./reveals/reveals.mjs";
4
5
  import Reveals from "../../Reveals.mjs";
5
- import Space from "../../Space.mjs";
6
- import { Collapse } from "./collapse.mjs";
7
- import { Dropdown } from "./dropdown.mjs";
6
+ import Space, { Props as Props$3 } from "../../Space.mjs";
7
+ import { Collapse, Props as Props$4 } from "./collapse.mjs";
8
+ import { Dropdown, Props as Props$5 } from "./dropdown.mjs";
9
+ import { Props as Props$6 } from "./marquees/marquees.mjs";
8
10
  import { Marquees } from "./marquees/index.mjs";
11
+ import { Props as Props$7 } from "./splitter/splitter.mjs";
9
12
  import { Splitter } from "./splitter/index.mjs";
10
- import { Upload, UploadFile } from "./upload.mjs";
13
+ import { Props as Props$8, Upload, UploadFile } from "./upload.mjs";
@@ -22,7 +22,7 @@ const getItemClasses = (root, isHorizontal, isInline, hasChildren, customClasses
22
22
  isHorizontal ? "border-b-2" : "border-r-2",
23
23
  isInline && "border-none"
24
24
  ] : ["rounded-md", ...STYLES.hover.classes], customClasses);
25
- const Item = ({ itemKey, keyPath, root = false, mode, label, children, selectedKeys = [], selectionMap, classNames, styles, offset = OFFSET, inlineOffset = INLINE_OFFSET, onClick, onSelect, ...props }) => {
25
+ const Item = ({ itemKey, keyPath, root = false, index, mode, label, children, selectionMap, classNames, styles, offset = OFFSET, inlineOffset = INLINE_OFFSET, onClick, onSelect, ...props }) => {
26
26
  const [open, setOpen] = useState(false);
27
27
  const itemRef = useRef(null);
28
28
  const isHorizontal = mode === "horizontal";
@@ -48,10 +48,30 @@ const Item = ({ itemKey, keyPath, root = false, mode, label, children, selectedK
48
48
  onClick?.(params);
49
49
  if (!selected) onSelect?.(params);
50
50
  };
51
+ const handleKeyDown = (domEvent) => {
52
+ if (domEvent.key === "Enter" || domEvent.key === " ") {
53
+ domEvent.preventDefault();
54
+ handleSelect(domEvent);
55
+ return;
56
+ }
57
+ if (domEvent.key === "Escape") {
58
+ if (children?.length && open) {
59
+ domEvent.stopPropagation();
60
+ setOpen(false);
61
+ }
62
+ return;
63
+ }
64
+ const isNext = isHorizontal ? domEvent.key === "ArrowRight" : domEvent.key === "ArrowDown";
65
+ const isPrev = isHorizontal ? domEvent.key === "ArrowLeft" : domEvent.key === "ArrowUp";
66
+ if (!isNext && !isPrev) return;
67
+ domEvent.preventDefault();
68
+ (isNext ? itemRef.current?.nextElementSibling : itemRef.current?.previousElementSibling)?.querySelector("[role=\"menuitem\"]")?.focus();
69
+ };
51
70
  const childrenContainerClassNames = cn(isInline ? "relative overflow-hidden" : "absolute min-w-[200px]", !isInline && root && isHorizontal ? "left-0 top-full pt-2 pl-0" : !isInline ? "left-full top-0 pl-2 pt-0" : "pl-4");
52
71
  const childrenContainerStyle = isInline ? { paddingLeft: inlineOffset } : root && isHorizontal ? { paddingTop: top } : { paddingLeft: left };
53
72
  return /* @__PURE__ */ jsxs("li", {
54
73
  ref: itemRef,
74
+ role: "none",
55
75
  className: cn("group", "relative", root && isHorizontal ? "inline-block" : "block"),
56
76
  onMouseEnter: () => {
57
77
  if (isInline) return;
@@ -71,19 +91,14 @@ const Item = ({ itemKey, keyPath, root = false, mode, label, children, selectedK
71
91
  },
72
92
  children: [/* @__PURE__ */ jsx("div", {
73
93
  role: "menuitem",
74
- tabIndex: 0,
94
+ tabIndex: index === 0 ? 0 : -1,
75
95
  "aria-expanded": children?.length ? open : void 0,
76
96
  "aria-haspopup": children?.length ? "menu" : void 0,
77
- "aria-selected": selected,
97
+ "aria-current": selected ? true : void 0,
78
98
  className: cn(itemClassNames, ...selected ? root ? ["border-current"] : [...STYLES.open.classes, ...STYLES.hover.classes] : root && !!children?.length ? ["group-hover:border-current"] : []),
79
99
  style: root ? styles?.rootItem : styles?.item,
80
100
  onClick: handleSelect,
81
- onKeyDown: (e) => {
82
- if (e.key === "Enter" || e.key === " ") {
83
- e.preventDefault();
84
- handleSelect(e);
85
- }
86
- },
101
+ onKeyDown: handleKeyDown,
87
102
  children: /* @__PURE__ */ jsxs("div", {
88
103
  className: cn("w-full", "inline-flex items-center justify-between"),
89
104
  children: [
@@ -113,16 +128,17 @@ const Item = ({ itemKey, keyPath, root = false, mode, label, children, selectedK
113
128
  } : { opacity: 0 },
114
129
  transition: { duration: .2 },
115
130
  children: /* @__PURE__ */ jsx("ul", {
131
+ role: "menu",
116
132
  className: cn(MENU_CLASSNAMES, isInline && "shadow-none", classNames?.subMenu),
117
133
  style: styles?.subMenu,
118
- children: children.map((child) => /* @__PURE__ */ createElement(Item, {
134
+ children: children.map((child, childIndex) => /* @__PURE__ */ createElement(Item, {
119
135
  ...child,
120
136
  key: child.key,
121
137
  itemKey: child.key,
122
138
  keyPath: [...keyPath, child.key],
139
+ index: childIndex,
123
140
  selectionMap,
124
141
  mode,
125
- selectedKeys,
126
142
  classNames,
127
143
  styles,
128
144
  offset,
@@ -1 +1 @@
1
- {"version":3,"file":"item.mjs","names":[],"sources":["../../../../../src/components/molecules/menu/item/item.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { ChevronDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { MENU_CLASSNAMES, MenuItem, Props } from '../menu';\nimport Label from './label';\n\ninterface ItemProps extends Props, MenuItem {\n itemKey: React.Key;\n keyPath: React.Key[];\n root?: boolean;\n}\nconst OFFSET: [number, number] = [8, 8];\nconst INLINE_OFFSET = 16;\n\nconst STYLES = {\n hover: {\n classes: ['hover:underline', 'hover:underline-offset-8'],\n },\n open: {\n classes: ['underline', 'underline-offset-8'],\n },\n} as const;\n\nconst getItemClasses = (\n root: boolean,\n isHorizontal: boolean,\n isInline: boolean,\n hasChildren: boolean,\n customClasses?: string,\n) =>\n cn(\n 'px-4 py-2',\n 'cursor-pointer',\n 'whitespace-nowrap',\n root && isHorizontal ? 'inline-flex' : 'flex',\n ...(root\n ? [\n 'h-full',\n 'rounded-none border-transparent',\n hasChildren && 'hover:border-current',\n isHorizontal ? 'border-b-2' : 'border-r-2',\n isInline && 'border-none',\n ]\n : ['rounded-md', ...STYLES.hover.classes]),\n customClasses,\n );\n\nconst Item = ({\n itemKey,\n keyPath,\n root = false,\n mode,\n label,\n children,\n selectedKeys = [],\n selectionMap,\n classNames,\n styles,\n offset = OFFSET,\n inlineOffset = INLINE_OFFSET,\n onClick,\n onSelect,\n ...props\n}: ItemProps) => {\n const [open, setOpen] = useState<boolean>(false);\n\n const itemRef = useRef<HTMLLIElement | null>(null);\n\n const isHorizontal = mode === 'horizontal';\n const isInline = mode === 'inline';\n\n const [left, top] = offset;\n\n const selected = selectionMap?.get(itemKey) ?? false;\n\n const item = {\n ...props,\n label,\n key: itemKey,\n children,\n };\n\n const itemClassNames = getItemClasses(\n root,\n isHorizontal,\n isInline,\n !!children?.length,\n root ? classNames?.rootItem : classNames?.item,\n );\n\n const handleSelect = (domEvent: React.SyntheticEvent) => {\n domEvent.stopPropagation();\n\n if (isInline) {\n setOpen(!open);\n }\n\n const params = {\n domEvent,\n key: itemKey,\n keyPath,\n item,\n };\n\n onClick?.(params);\n\n if (!selected) {\n onSelect?.(params);\n }\n };\n\n const childrenContainerClassNames = cn(\n isInline ? 'relative overflow-hidden' : 'absolute min-w-[200px]',\n !isInline && root && isHorizontal\n ? 'left-0 top-full pt-2 pl-0'\n : !isInline\n ? 'left-full top-0 pl-2 pt-0'\n : 'pl-4',\n );\n\n const childrenContainerStyle = isInline\n ? {\n paddingLeft: inlineOffset,\n }\n : root && isHorizontal\n ? {\n paddingTop: top,\n }\n : {\n paddingLeft: left,\n };\n\n return (\n <li\n ref={itemRef}\n className={cn(\n 'group',\n 'relative',\n root && isHorizontal ? 'inline-block' : 'block',\n )}\n onMouseEnter={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onMouseLeave={() => {\n if (isInline) {\n return;\n }\n setOpen(false);\n }}\n onFocus={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onBlur={e => {\n if (isInline) {\n return;\n }\n if (!itemRef.current?.contains(e.relatedTarget as Node)) {\n setOpen(false);\n }\n }}\n >\n <div\n role=\"menuitem\"\n tabIndex={0}\n aria-expanded={children?.length ? open : undefined}\n aria-haspopup={children?.length ? 'menu' : undefined}\n aria-selected={selected}\n className={cn(\n itemClassNames,\n ...(selected\n ? root\n ? ['border-current']\n : [...STYLES.open.classes, ...STYLES.hover.classes]\n : root && !!children?.length\n ? ['group-hover:border-current']\n : []),\n //\n )}\n style={root ? styles?.rootItem : styles?.item}\n onClick={handleSelect}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelect(e);\n }\n }}\n >\n <div\n className={cn(\n 'w-full',\n 'inline-flex items-center justify-between',\n //\n )}\n >\n <Label className={cn(classNames?.label)} style={styles?.label}>\n {label}\n </Label>\n {!root && !isInline && !!children?.length && (\n <ChevronDown className={cn('-rotate-90')} />\n )}\n {isInline && !!children?.length && (\n <ChevronDown\n className={cn(\n 'transition-all',\n open ? '-rotate-180' : 'rotate-0',\n )}\n />\n )}\n </div>\n </div>\n <AnimatePresence>\n {!!children?.length && open && (\n <motion.div\n className={cn(\n childrenContainerClassNames,\n //\n )}\n style={childrenContainerStyle}\n initial={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n animate={isInline ? { height: 'auto', opacity: 1 } : { opacity: 1 }}\n exit={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <ul\n className={cn(\n MENU_CLASSNAMES,\n isInline && 'shadow-none',\n classNames?.subMenu,\n //\n )}\n style={styles?.subMenu}\n >\n {children.map(child => (\n <Item\n {...child}\n key={child.key}\n itemKey={child.key}\n keyPath={[...keyPath, child.key]}\n selectionMap={selectionMap}\n mode={mode}\n selectedKeys={selectedKeys}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n </motion.div>\n )}\n </AnimatePresence>\n </li>\n );\n};\n\nexport default Item;\n"],"mappings":"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"}
1
+ {"version":3,"file":"item.mjs","names":[],"sources":["../../../../../src/components/molecules/menu/item/item.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { ChevronDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { MENU_CLASSNAMES, MenuItem, Props } from '../menu';\nimport Label from './label';\n\ninterface ItemProps extends Props, MenuItem {\n itemKey: React.Key;\n keyPath: React.Key[];\n root?: boolean;\n index: number;\n}\nconst OFFSET: [number, number] = [8, 8];\nconst INLINE_OFFSET = 16;\n\nconst STYLES = {\n hover: {\n classes: ['hover:underline', 'hover:underline-offset-8'],\n },\n open: {\n classes: ['underline', 'underline-offset-8'],\n },\n} as const;\n\nconst getItemClasses = (\n root: boolean,\n isHorizontal: boolean,\n isInline: boolean,\n hasChildren: boolean,\n customClasses?: string,\n) =>\n cn(\n 'px-4 py-2',\n 'cursor-pointer',\n 'whitespace-nowrap',\n root && isHorizontal ? 'inline-flex' : 'flex',\n ...(root\n ? [\n 'h-full',\n 'rounded-none border-transparent',\n hasChildren && 'hover:border-current',\n isHorizontal ? 'border-b-2' : 'border-r-2',\n isInline && 'border-none',\n ]\n : ['rounded-md', ...STYLES.hover.classes]),\n customClasses,\n );\n\nconst Item = ({\n itemKey,\n keyPath,\n root = false,\n index,\n mode,\n label,\n children,\n selectionMap,\n classNames,\n styles,\n offset = OFFSET,\n inlineOffset = INLINE_OFFSET,\n onClick,\n onSelect,\n ...props\n}: ItemProps) => {\n const [open, setOpen] = useState<boolean>(false);\n\n const itemRef = useRef<HTMLLIElement | null>(null);\n\n const isHorizontal = mode === 'horizontal';\n const isInline = mode === 'inline';\n\n const [left, top] = offset;\n\n const selected = selectionMap?.get(itemKey) ?? false;\n\n const item = {\n ...props,\n label,\n key: itemKey,\n children,\n };\n\n const itemClassNames = getItemClasses(\n root,\n isHorizontal,\n isInline,\n !!children?.length,\n root ? classNames?.rootItem : classNames?.item,\n );\n\n const handleSelect = (domEvent: React.SyntheticEvent) => {\n domEvent.stopPropagation();\n\n if (isInline) {\n setOpen(!open);\n }\n\n const params = {\n domEvent,\n key: itemKey,\n keyPath,\n item,\n };\n\n onClick?.(params);\n\n if (!selected) {\n onSelect?.(params);\n }\n };\n\n // Roving tabindex (WAI-ARIA menu pattern): only the first item in each\n // menu/submenu level is a Tab stop (below); arrow keys move real DOM\n // focus between sibling <li>s within that same level, which is what\n // ends up mattering for actual keyboard use even though — unlike a\n // fully state-tracked implementation — focus resets to the first item\n // if the user Tabs out and back in rather than resuming where they left\n // off.\n const handleKeyDown = (domEvent: React.KeyboardEvent) => {\n if (domEvent.key === 'Enter' || domEvent.key === ' ') {\n domEvent.preventDefault();\n handleSelect(domEvent);\n return;\n }\n\n if (domEvent.key === 'Escape') {\n if (children?.length && open) {\n domEvent.stopPropagation();\n setOpen(false);\n }\n return;\n }\n\n const isNext = isHorizontal\n ? domEvent.key === 'ArrowRight'\n : domEvent.key === 'ArrowDown';\n const isPrev = isHorizontal\n ? domEvent.key === 'ArrowLeft'\n : domEvent.key === 'ArrowUp';\n\n if (!isNext && !isPrev) {\n return;\n }\n\n domEvent.preventDefault();\n const sibling = isNext\n ? itemRef.current?.nextElementSibling\n : itemRef.current?.previousElementSibling;\n sibling?.querySelector<HTMLElement>('[role=\"menuitem\"]')?.focus();\n };\n\n const childrenContainerClassNames = cn(\n isInline ? 'relative overflow-hidden' : 'absolute min-w-[200px]',\n !isInline && root && isHorizontal\n ? 'left-0 top-full pt-2 pl-0'\n : !isInline\n ? 'left-full top-0 pl-2 pt-0'\n : 'pl-4',\n );\n\n const childrenContainerStyle = isInline\n ? {\n paddingLeft: inlineOffset,\n }\n : root && isHorizontal\n ? {\n paddingTop: top,\n }\n : {\n paddingLeft: left,\n };\n\n return (\n <li\n ref={itemRef}\n role=\"none\"\n className={cn(\n 'group',\n 'relative',\n root && isHorizontal ? 'inline-block' : 'block',\n )}\n onMouseEnter={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onMouseLeave={() => {\n if (isInline) {\n return;\n }\n setOpen(false);\n }}\n onFocus={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onBlur={e => {\n if (isInline) {\n return;\n }\n if (!itemRef.current?.contains(e.relatedTarget as Node)) {\n setOpen(false);\n }\n }}\n >\n <div\n role=\"menuitem\"\n tabIndex={index === 0 ? 0 : -1}\n aria-expanded={children?.length ? open : undefined}\n aria-haspopup={children?.length ? 'menu' : undefined}\n aria-current={selected ? true : undefined}\n className={cn(\n itemClassNames,\n ...(selected\n ? root\n ? ['border-current']\n : [...STYLES.open.classes, ...STYLES.hover.classes]\n : root && !!children?.length\n ? ['group-hover:border-current']\n : []),\n //\n )}\n style={root ? styles?.rootItem : styles?.item}\n onClick={handleSelect}\n onKeyDown={handleKeyDown}\n >\n <div\n className={cn(\n 'w-full',\n 'inline-flex items-center justify-between',\n //\n )}\n >\n <Label className={cn(classNames?.label)} style={styles?.label}>\n {label}\n </Label>\n {!root && !isInline && !!children?.length && (\n <ChevronDown className={cn('-rotate-90')} />\n )}\n {isInline && !!children?.length && (\n <ChevronDown\n className={cn(\n 'transition-all',\n open ? '-rotate-180' : 'rotate-0',\n )}\n />\n )}\n </div>\n </div>\n <AnimatePresence>\n {!!children?.length && open && (\n <motion.div\n className={cn(\n childrenContainerClassNames,\n //\n )}\n style={childrenContainerStyle}\n initial={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n animate={isInline ? { height: 'auto', opacity: 1 } : { opacity: 1 }}\n exit={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <ul\n role=\"menu\"\n className={cn(\n MENU_CLASSNAMES,\n isInline && 'shadow-none',\n classNames?.subMenu,\n //\n )}\n style={styles?.subMenu}\n >\n {children.map((child, childIndex) => (\n <Item\n {...child}\n key={child.key}\n itemKey={child.key}\n keyPath={[...keyPath, child.key]}\n index={childIndex}\n selectionMap={selectionMap}\n mode={mode}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n </motion.div>\n )}\n </AnimatePresence>\n </li>\n );\n};\n\nexport default Item;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"menu.d.mts","names":[],"sources":["../../../../src/components/molecules/menu/menu.tsx"],"mappings":";;;UAQiB,QAAA;EACf,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,GAAA,EAAK,KAAA,CAAM,GAAA;EACX,IAAA;EACA,IAAA;EACA,QAAA,GAAW,QAAA;AAAA;AAAA,UAGI,KAAA;EACf,IAAA;EACA,YAAA,GAAe,KAAA,CAAM,GAAA;EACrB,mBAAA,GAAsB,KAAA,CAAM,GAAA;EAC5B,YAAA,GAAe,YAAA;EACf,MAAA;EACA,YAAA;EACA,UAAA;IACE,QAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;EAAA;EAGF,MAAA;IACE,QAAA,GAAW,KAAA,CAAM,aAAA;IACjB,OAAA,GAAU,KAAA,CAAM,aAAA;IAChB,IAAA,GAAO,KAAA,CAAM,aAAA;IACb,KAAA,GAAQ,KAAA,CAAM,aAAA;EAAA;EAGhB,OAAA,GAAU,iBAAA;EACV,QAAA,GAAW,iBAAA;AAAA;AAAA,UAGI,SAAA,SAEb,KAAA,EACA,IAAA,CAAK,KAAA,CAAM,wBAAA;EACb,KAAA,GAAQ,QAAA;AAAA;AAAA,KAGE,iBAAA,IAAqB,MAAA;EAC/B,QAAA,EAAU,KAAA,CAAM,cAAA;EAChB,GAAA,EAAK,KAAA,CAAM,GAAA;EACX,OAAA,EAAS,KAAA,CAAM,GAAA;EACf,IAAA,EAAM,QAAA;AAAA;AAAA,cAGK,eAAA;AAAA,KASD,YAAA,GAAe,WAAA,CAAY,KAAA,CAAM,GAAA;AAAA,cAEhC,iBAAA,GACX,KAAA,EAAO,QAAA,IACP,eAAA,EAAiB,WAAA,CAAY,KAAA,CAAM,GAAA,MAClC,YAAA;AAAA,cAeU,OAAA,GACX,IAAA,EAAM,QAAA,EACN,UAAA,EAAY,WAAA,CAAY,KAAA,CAAM,GAAA;AAAA,cAiB1B,IAAA;EAAQ,KAAA;EAAA,IAAA;EAAA,mBAAA;EAAA,YAAA,EAAA,aAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAA,MAAA;EAAA,YAAA;EAAA,OAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAaX,SAAA,KAAS,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"menu.d.mts","names":[],"sources":["../../../../src/components/molecules/menu/menu.tsx"],"mappings":";;;UAUiB,QAAA;EACf,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,GAAA,EAAK,KAAA,CAAM,GAAA;EACX,IAAA;EACA,IAAA;EACA,QAAA,GAAW,QAAA;AAAA;AAAA,UAGI,KAAA;EACf,IAAA;EACA,YAAA,GAAe,KAAA,CAAM,GAAA;EACrB,mBAAA,GAAsB,KAAA,CAAM,GAAA;EAC5B,YAAA,GAAe,YAAA;EACf,MAAA;EACA,YAAA;EACA,UAAA;IACE,QAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;EAAA;EAEF,MAAA;IACE,QAAA,GAAW,KAAA,CAAM,aAAA;IACjB,OAAA,GAAU,KAAA,CAAM,aAAA;IAChB,IAAA,GAAO,KAAA,CAAM,aAAA;IACb,KAAA,GAAQ,KAAA,CAAM,aAAA;EAAA;EAEhB,OAAA,GAAU,iBAAA;EACV,QAAA,GAAW,iBAAA;AAAA;AAAA,UAGI,SAAA,SAEb,KAAA,EACA,IAAA,CAAK,KAAA,CAAM,wBAAA;EACb,KAAA,GAAQ,QAAA;AAAA;AAAA,KAGE,iBAAA,IAAqB,MAAA;EAC/B,QAAA,EAAU,KAAA,CAAM,cAAA;EAChB,GAAA,EAAK,KAAA,CAAM,GAAA;EACX,OAAA,EAAS,KAAA,CAAM,GAAA;EACf,IAAA,EAAM,QAAA;AAAA;AAAA,cAGK,eAAA;AAAA,KASD,YAAA,GAAe,WAAA,CAAY,KAAA,CAAM,GAAA;AAAA,cAEhC,iBAAA,GACX,KAAA,EAAO,QAAA,IACP,eAAA,EAAiB,WAAA,CAAY,KAAA,CAAM,GAAA,MAClC,YAAA;AAAA,cAeU,OAAA,GACX,IAAA,EAAM,QAAA,EACN,UAAA,EAAY,WAAA,CAAY,KAAA,CAAM,GAAA;AAAA,cAiB1B,IAAA;EAAQ,KAAA;EAAA,IAAA;EAAA,mBAAA;EAAA,YAAA,EAAA,aAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAA,MAAA;EAAA,YAAA;EAAA,OAAA;EAAA,QAAA,EAAA,SAAA;EAAA,GAAA;AAAA,GAaX,SAAA,KAAS,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -2,8 +2,9 @@
2
2
 
3
3
  import { cn } from "../../../utils.mjs";
4
4
  import Item from "./item/item.mjs";
5
- import { createElement, useMemo, useState } from "react";
5
+ import { createElement, useMemo } from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
+ import { useControllableState } from "@jbpark/use-hooks";
7
8
 
8
9
  //#region src/components/molecules/menu/menu.tsx
9
10
  const MENU_CLASSNAMES = [
@@ -33,26 +34,27 @@ const findKey = (menu, targetKeys) => {
33
34
  return false;
34
35
  };
35
36
  const Menu = ({ items, mode = "vertical", defaultSelectedKeys = [], selectedKeys: _selectedKeys, className, classNames, styles, offset, inlineOffset, onClick, onSelect: _onSelect, ...props }) => {
36
- const controlled = _selectedKeys !== void 0;
37
- const [uncontrolledSelectedKeys, setUncontrolledSelectedKeys] = useState(defaultSelectedKeys ?? []);
38
- const selectedKeys = controlled ? _selectedKeys : uncontrolledSelectedKeys;
37
+ const [selectedKeys, setSelectedKeys] = useControllableState({
38
+ value: _selectedKeys,
39
+ defaultValue: defaultSelectedKeys ?? []
40
+ });
39
41
  const selectedKeysSet = useMemo(() => new Set(selectedKeys ?? []), [selectedKeys]);
40
42
  const selectionMap = useMemo(() => buildSelectionMap(items ?? [], selectedKeysSet), [items, selectedKeysSet]);
41
43
  const onSelect = (params) => {
42
- if (!controlled) setUncontrolledSelectedKeys([params.key]);
44
+ setSelectedKeys([params.key]);
43
45
  _onSelect?.(params);
44
46
  };
45
47
  return /* @__PURE__ */ jsx("ul", {
46
48
  role: "menu",
47
49
  className: cn(MENU_CLASSNAMES, mode === "horizontal" ? "flex" : "inline-block", className),
48
50
  ...props,
49
- children: items?.map((item) => /* @__PURE__ */ createElement(Item, {
51
+ children: items?.map((item, index) => /* @__PURE__ */ createElement(Item, {
50
52
  root: true,
51
53
  ...item,
52
54
  key: item.key,
53
55
  itemKey: item.key,
54
56
  keyPath: [item.key],
55
- selectedKeys,
57
+ index,
56
58
  selectionMap,
57
59
  mode,
58
60
  classNames,
@@ -1 +1 @@
1
- {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../src/components/molecules/menu/menu.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Item from './item';\n\nexport interface MenuItem {\n label: React.ReactNode;\n key: React.Key;\n type?: string;\n path?: string;\n children?: MenuItem[];\n}\n\nexport interface Props {\n mode?: 'horizontal' | 'vertical' | 'inline';\n selectedKeys?: React.Key[];\n defaultSelectedKeys?: React.Key[];\n selectionMap?: SelectionMap;\n offset?: [number, number];\n inlineOffset?: number;\n classNames?: {\n rootItem?: string;\n subMenu?: string;\n item?: string;\n label?: string;\n // open?: string;\n };\n styles?: {\n rootItem?: React.CSSProperties;\n subMenu?: React.CSSProperties;\n item?: React.CSSProperties;\n label?: React.CSSProperties;\n // open?: React.CSSProperties;\n };\n onClick?: ClickEventHandler;\n onSelect?: ClickEventHandler;\n}\n\nexport interface MenuProps\n extends\n Props,\n Omit<React.ComponentPropsWithoutRef<'ul'>, 'onClick' | 'onSelect'> {\n items?: MenuItem[];\n}\n\nexport type ClickEventHandler = (params: {\n domEvent: React.SyntheticEvent;\n key: React.Key;\n keyPath: React.Key[];\n item: MenuItem;\n}) => void;\n\nexport const MENU_CLASSNAMES = [\n 'p-0',\n 'bg-popover',\n 'text-popover-foreground',\n 'shadow-md',\n 'rounded-md',\n //\n];\n\nexport type SelectionMap = ReadonlyMap<React.Key, boolean>;\n\nexport const buildSelectionMap = (\n items: MenuItem[],\n selectedKeysSet: ReadonlySet<React.Key>,\n): SelectionMap => {\n const map = new Map<React.Key, boolean>();\n\n const dfs = (node: MenuItem): boolean => {\n const self = selectedKeysSet.has(node.key);\n const hasSelectedChild = node.children?.some(child => dfs(child)) ?? false;\n const isSelected = self || hasSelectedChild;\n map.set(node.key, isSelected);\n return isSelected;\n };\n\n items.forEach(dfs);\n return map;\n};\n\nexport const findKey = (\n menu: MenuItem,\n targetKeys: ReadonlySet<React.Key>,\n): boolean => {\n if (targetKeys.has(menu.key)) {\n return true;\n }\n\n if (menu.children && Array.isArray(menu.children)) {\n for (const child of menu.children) {\n if (findKey(child, targetKeys)) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nconst Menu = ({\n items,\n mode = 'vertical',\n defaultSelectedKeys = [],\n selectedKeys: _selectedKeys,\n className,\n classNames,\n styles,\n offset,\n inlineOffset,\n onClick,\n onSelect: _onSelect,\n ...props\n}: MenuProps) => {\n const controlled = _selectedKeys !== undefined;\n const [uncontrolledSelectedKeys, setUncontrolledSelectedKeys] = useState<\n React.Key[]\n >(defaultSelectedKeys ?? []);\n\n const selectedKeys = controlled\n ? (_selectedKeys as React.Key[])\n : uncontrolledSelectedKeys;\n\n const selectedKeysSet = useMemo(\n () => new Set<React.Key>(selectedKeys ?? []),\n [selectedKeys],\n );\n\n const selectionMap = useMemo(\n () => buildSelectionMap(items ?? [], selectedKeysSet),\n [items, selectedKeysSet],\n );\n\n const onSelect = (params: {\n domEvent: React.SyntheticEvent;\n key: React.Key;\n keyPath: React.Key[];\n item: MenuItem;\n }) => {\n if (!controlled) {\n setUncontrolledSelectedKeys([params.key]);\n }\n _onSelect?.(params);\n };\n\n return (\n <ul\n role=\"menu\"\n className={cn(\n MENU_CLASSNAMES,\n mode === 'horizontal' ? 'flex' : 'inline-block',\n className,\n )}\n {...props}\n >\n {items?.map(item => (\n <Item\n root\n {...item}\n key={item.key}\n itemKey={item.key}\n keyPath={[item.key]}\n selectedKeys={selectedKeys}\n selectionMap={selectionMap}\n mode={mode}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n );\n};\n\nexport default Menu;\n"],"mappings":";;;;;;;;AAuDA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;CAED;AAID,MAAa,qBACX,OACA,oBACiB;CACjB,MAAM,sBAAM,IAAI,KAAyB;CAEzC,MAAM,OAAO,SAA4B;EACvC,MAAM,OAAO,gBAAgB,IAAI,KAAK,IAAI;EAC1C,MAAM,mBAAmB,KAAK,UAAU,MAAK,UAAS,IAAI,MAAM,CAAC,IAAI;EACrE,MAAM,aAAa,QAAQ;AAC3B,MAAI,IAAI,KAAK,KAAK,WAAW;AAC7B,SAAO;;AAGT,OAAM,QAAQ,IAAI;AAClB,QAAO;;AAGT,MAAa,WACX,MACA,eACY;AACZ,KAAI,WAAW,IAAI,KAAK,IAAI,CAC1B,QAAO;AAGT,KAAI,KAAK,YAAY,MAAM,QAAQ,KAAK,SAAS,EAC/C;OAAK,MAAM,SAAS,KAAK,SACvB,KAAI,QAAQ,OAAO,WAAW,CAC5B,QAAO;;AAKb,QAAO;;AAGT,MAAM,QAAQ,EACZ,OACA,OAAO,YACP,sBAAsB,EAAE,EACxB,cAAc,eACd,WACA,YACA,QACA,QACA,cACA,SACA,UAAU,WACV,GAAG,YACY;CACf,MAAM,aAAa,kBAAkB;CACrC,MAAM,CAAC,0BAA0B,+BAA+B,SAE9D,uBAAuB,EAAE,CAAC;CAE5B,MAAM,eAAe,aAChB,gBACD;CAEJ,MAAM,kBAAkB,cAChB,IAAI,IAAe,gBAAgB,EAAE,CAAC,EAC5C,CAAC,aAAa,CACf;CAED,MAAM,eAAe,cACb,kBAAkB,SAAS,EAAE,EAAE,gBAAgB,EACrD,CAAC,OAAO,gBAAgB,CACzB;CAED,MAAM,YAAY,WAKZ;AACJ,MAAI,CAAC,WACH,6BAA4B,CAAC,OAAO,IAAI,CAAC;AAE3C,cAAY,OAAO;;AAGrB,QACE,oBAAC;EACC,MAAK;EACL,WAAW,GACT,iBACA,SAAS,eAAe,SAAS,gBACjC,UACD;EACD,GAAI;YAEH,OAAO,KAAI,SACV,8BAAC;GACC;GACA,GAAI;GACJ,KAAK,KAAK;GACV,SAAS,KAAK;GACd,SAAS,CAAC,KAAK,IAAI;GACL;GACA;GACR;GACM;GACJ;GACA;GACM;GACL;GACC;IACV,CACF;GACC"}
1
+ {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../src/components/molecules/menu/menu.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Item from './item';\n\nexport interface MenuItem {\n label: React.ReactNode;\n key: React.Key;\n type?: string;\n path?: string;\n children?: MenuItem[];\n}\n\nexport interface Props {\n mode?: 'horizontal' | 'vertical' | 'inline';\n selectedKeys?: React.Key[];\n defaultSelectedKeys?: React.Key[];\n selectionMap?: SelectionMap;\n offset?: [number, number];\n inlineOffset?: number;\n classNames?: {\n rootItem?: string;\n subMenu?: string;\n item?: string;\n label?: string;\n };\n styles?: {\n rootItem?: React.CSSProperties;\n subMenu?: React.CSSProperties;\n item?: React.CSSProperties;\n label?: React.CSSProperties;\n };\n onClick?: ClickEventHandler;\n onSelect?: ClickEventHandler;\n}\n\nexport interface MenuProps\n extends\n Props,\n Omit<React.ComponentPropsWithoutRef<'ul'>, 'onClick' | 'onSelect'> {\n items?: MenuItem[];\n}\n\nexport type ClickEventHandler = (params: {\n domEvent: React.SyntheticEvent;\n key: React.Key;\n keyPath: React.Key[];\n item: MenuItem;\n}) => void;\n\nexport const MENU_CLASSNAMES = [\n 'p-0',\n 'bg-popover',\n 'text-popover-foreground',\n 'shadow-md',\n 'rounded-md',\n //\n];\n\nexport type SelectionMap = ReadonlyMap<React.Key, boolean>;\n\nexport const buildSelectionMap = (\n items: MenuItem[],\n selectedKeysSet: ReadonlySet<React.Key>,\n): SelectionMap => {\n const map = new Map<React.Key, boolean>();\n\n const dfs = (node: MenuItem): boolean => {\n const self = selectedKeysSet.has(node.key);\n const hasSelectedChild = node.children?.some(child => dfs(child)) ?? false;\n const isSelected = self || hasSelectedChild;\n map.set(node.key, isSelected);\n return isSelected;\n };\n\n items.forEach(dfs);\n return map;\n};\n\nexport const findKey = (\n menu: MenuItem,\n targetKeys: ReadonlySet<React.Key>,\n): boolean => {\n if (targetKeys.has(menu.key)) {\n return true;\n }\n\n if (menu.children && Array.isArray(menu.children)) {\n for (const child of menu.children) {\n if (findKey(child, targetKeys)) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nconst Menu = ({\n items,\n mode = 'vertical',\n defaultSelectedKeys = [],\n selectedKeys: _selectedKeys,\n className,\n classNames,\n styles,\n offset,\n inlineOffset,\n onClick,\n onSelect: _onSelect,\n ...props\n}: MenuProps) => {\n const [selectedKeys, setSelectedKeys] = useControllableState<React.Key[]>({\n value: _selectedKeys,\n defaultValue: defaultSelectedKeys ?? [],\n });\n\n const selectedKeysSet = useMemo(\n () => new Set<React.Key>(selectedKeys ?? []),\n [selectedKeys],\n );\n\n const selectionMap = useMemo(\n () => buildSelectionMap(items ?? [], selectedKeysSet),\n [items, selectedKeysSet],\n );\n\n const onSelect = (params: {\n domEvent: React.SyntheticEvent;\n key: React.Key;\n keyPath: React.Key[];\n item: MenuItem;\n }) => {\n setSelectedKeys([params.key]);\n _onSelect?.(params);\n };\n\n return (\n <ul\n role=\"menu\"\n className={cn(\n MENU_CLASSNAMES,\n mode === 'horizontal' ? 'flex' : 'inline-block',\n className,\n )}\n {...props}\n >\n {items?.map((item, index) => (\n <Item\n root\n {...item}\n key={item.key}\n itemKey={item.key}\n keyPath={[item.key]}\n index={index}\n selectionMap={selectionMap}\n mode={mode}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n );\n};\n\nexport default Menu;\n"],"mappings":";;;;;;;;;AAuDA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;CAED;AAID,MAAa,qBACX,OACA,oBACiB;CACjB,MAAM,sBAAM,IAAI,KAAyB;CAEzC,MAAM,OAAO,SAA4B;EACvC,MAAM,OAAO,gBAAgB,IAAI,KAAK,IAAI;EAC1C,MAAM,mBAAmB,KAAK,UAAU,MAAK,UAAS,IAAI,MAAM,CAAC,IAAI;EACrE,MAAM,aAAa,QAAQ;AAC3B,MAAI,IAAI,KAAK,KAAK,WAAW;AAC7B,SAAO;;AAGT,OAAM,QAAQ,IAAI;AAClB,QAAO;;AAGT,MAAa,WACX,MACA,eACY;AACZ,KAAI,WAAW,IAAI,KAAK,IAAI,CAC1B,QAAO;AAGT,KAAI,KAAK,YAAY,MAAM,QAAQ,KAAK,SAAS,EAC/C;OAAK,MAAM,SAAS,KAAK,SACvB,KAAI,QAAQ,OAAO,WAAW,CAC5B,QAAO;;AAKb,QAAO;;AAGT,MAAM,QAAQ,EACZ,OACA,OAAO,YACP,sBAAsB,EAAE,EACxB,cAAc,eACd,WACA,YACA,QACA,QACA,cACA,SACA,UAAU,WACV,GAAG,YACY;CACf,MAAM,CAAC,cAAc,mBAAmB,qBAAkC;EACxE,OAAO;EACP,cAAc,uBAAuB,EAAE;EACxC,CAAC;CAEF,MAAM,kBAAkB,cAChB,IAAI,IAAe,gBAAgB,EAAE,CAAC,EAC5C,CAAC,aAAa,CACf;CAED,MAAM,eAAe,cACb,kBAAkB,SAAS,EAAE,EAAE,gBAAgB,EACrD,CAAC,OAAO,gBAAgB,CACzB;CAED,MAAM,YAAY,WAKZ;AACJ,kBAAgB,CAAC,OAAO,IAAI,CAAC;AAC7B,cAAY,OAAO;;AAGrB,QACE,oBAAC;EACC,MAAK;EACL,WAAW,GACT,iBACA,SAAS,eAAe,SAAS,gBACjC,UACD;EACD,GAAI;YAEH,OAAO,KAAK,MAAM,UACjB,8BAAC;GACC;GACA,GAAI;GACJ,KAAK,KAAK;GACV,SAAS,KAAK;GACd,SAAS,CAAC,KAAK,IAAI;GACZ;GACO;GACR;GACM;GACJ;GACA;GACM;GACL;GACC;IACV,CACF;GACC"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { cn } from "../../../utils.mjs";
4
4
  import { resizable_exports } from "../../../core/resizable.mjs";
5
- import { Children, Fragment } from "react";
5
+ import { Children, Fragment, isValidElement } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
 
8
8
  //#region src/components/molecules/splitter/splitter.tsx
@@ -20,7 +20,7 @@ const Splitter = ({ children, className, orientation = "horizontal", withHandle
20
20
  transition-colors`, handleClassName),
21
21
  withHandle: withHandle && handle === void 0,
22
22
  children: handle
23
- })] }, index))
23
+ })] }, isValidElement(panel) && panel.key != null ? panel.key : index))
24
24
  });
25
25
  };
26
26
 
@@ -1 +1 @@
1
- {"version":3,"file":"splitter.mjs","names":["resizable"],"sources":["../../../../src/components/molecules/splitter/splitter.tsx"],"sourcesContent":["'use client';\n\nimport { Children, Fragment } from 'react';\n\nimport { resizable } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nconst { ResizableHandle, ResizablePanelGroup } = resizable;\n\ntype SplitterLayout = Parameters<\n NonNullable<\n React.ComponentProps<typeof ResizablePanelGroup>['onLayoutChanged']\n >\n>[0];\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof ResizablePanelGroup>,\n 'children' | 'orientation' | 'onLayoutChange' | 'onLayoutChanged' | 'onResize'\n> {\n children: React.ReactNode;\n orientation?: 'horizontal' | 'vertical';\n withHandle?: boolean;\n handle?: React.ReactNode;\n handleClassName?: string;\n onResize?: (layout: SplitterLayout) => void;\n onResizeEnd?: (layout: SplitterLayout) => void;\n}\n\nconst Splitter = ({\n children,\n className,\n orientation = 'horizontal',\n withHandle = true,\n handle,\n handleClassName,\n onResize,\n onResizeEnd,\n ...props\n}: Props) => {\n const panels = Children.toArray(children);\n\n return (\n <ResizablePanelGroup\n className={cn(\n 'border-border/60 h-full w-full rounded-lg border',\n className,\n )}\n orientation={orientation}\n onLayoutChange={onResize}\n onLayoutChanged={onResizeEnd}\n {...props}\n >\n {panels.map((panel, index) => (\n <Fragment key={index}>\n {panel}\n {index < panels.length - 1 && (\n <ResizableHandle\n className={cn(\n `hover:bg-border/80 data-separator-active:bg-border\n transition-colors`,\n handleClassName,\n )}\n withHandle={withHandle && handle === undefined}\n >\n {handle}\n </ResizableHandle>\n )}\n </Fragment>\n ))}\n </ResizablePanelGroup>\n );\n};\n\nexport default Splitter;\n"],"mappings":";;;;;;;;AAOA,MAAM,EAAE,iBAAiB,wBAAwBA;AAqBjD,MAAM,YAAY,EAChB,UACA,WACA,cAAc,cACd,aAAa,MACb,QACA,iBACA,UACA,aACA,GAAG,YACQ;CACX,MAAM,SAAS,SAAS,QAAQ,SAAS;AAEzC,QACE,oBAAC;EACC,WAAW,GACT,oDACA,UACD;EACY;EACb,gBAAgB;EAChB,iBAAiB;EACjB,GAAI;YAEH,OAAO,KAAK,OAAO,UAClB,qBAAC,uBACE,OACA,QAAQ,OAAO,SAAS,KACvB,oBAAC;GACC,WAAW,GACT;oCAEA,gBACD;GACD,YAAY,cAAc,WAAW;aAEpC;IACe,KAZP,MAcJ,CACX;GACkB"}
1
+ {"version":3,"file":"splitter.mjs","names":["resizable"],"sources":["../../../../src/components/molecules/splitter/splitter.tsx"],"sourcesContent":["'use client';\n\nimport { Children, Fragment, isValidElement } from 'react';\n\nimport { resizable } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nconst { ResizableHandle, ResizablePanelGroup } = resizable;\n\ntype SplitterLayout = Parameters<\n NonNullable<\n React.ComponentProps<typeof ResizablePanelGroup>['onLayoutChanged']\n >\n>[0];\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof ResizablePanelGroup>,\n 'children' | 'orientation' | 'onLayoutChange' | 'onLayoutChanged' | 'onResize'\n> {\n children: React.ReactNode;\n orientation?: 'horizontal' | 'vertical';\n withHandle?: boolean;\n handle?: React.ReactNode;\n handleClassName?: string;\n onResize?: (layout: SplitterLayout) => void;\n onResizeEnd?: (layout: SplitterLayout) => void;\n}\n\nconst Splitter = ({\n children,\n className,\n orientation = 'horizontal',\n withHandle = true,\n handle,\n handleClassName,\n onResize,\n onResizeEnd,\n ...props\n}: Props) => {\n const panels = Children.toArray(children);\n\n return (\n <ResizablePanelGroup\n className={cn(\n 'border-border/60 h-full w-full rounded-lg border',\n className,\n )}\n orientation={orientation}\n onLayoutChange={onResize}\n onLayoutChanged={onResizeEnd}\n {...props}\n >\n {panels.map((panel, index) => (\n <Fragment\n key={isValidElement(panel) && panel.key != null ? panel.key : index}\n >\n {panel}\n {index < panels.length - 1 && (\n <ResizableHandle\n className={cn(\n `hover:bg-border/80 data-separator-active:bg-border\n transition-colors`,\n handleClassName,\n )}\n withHandle={withHandle && handle === undefined}\n >\n {handle}\n </ResizableHandle>\n )}\n </Fragment>\n ))}\n </ResizablePanelGroup>\n );\n};\n\nexport default Splitter;\n"],"mappings":";;;;;;;;AAOA,MAAM,EAAE,iBAAiB,wBAAwBA;AAqBjD,MAAM,YAAY,EAChB,UACA,WACA,cAAc,cACd,aAAa,MACb,QACA,iBACA,UACA,aACA,GAAG,YACQ;CACX,MAAM,SAAS,SAAS,QAAQ,SAAS;AAEzC,QACE,oBAAC;EACC,WAAW,GACT,oDACA,UACD;EACY;EACb,gBAAgB;EAChB,iBAAiB;EACjB,GAAI;YAEH,OAAO,KAAK,OAAO,UAClB,qBAAC,uBAGE,OACA,QAAQ,OAAO,SAAS,KACvB,oBAAC;GACC,WAAW,GACT;oCAEA,gBACD;GACD,YAAY,cAAc,WAAW;aAEpC;IACe,KAbf,eAAe,MAAM,IAAI,MAAM,OAAO,OAAO,MAAM,MAAM,MAerD,CACX;GACkB"}
@@ -42,5 +42,5 @@ declare const Upload: ({
42
42
  onReject
43
43
  }: Props) => react_jsx_runtime0.JSX.Element;
44
44
  //#endregion
45
- export { Upload, UploadFile };
45
+ export { Props, Upload, UploadFile };
46
46
  //# sourceMappingURL=upload.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;UA0CiB,KAAA;EACf,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,QAAA;EACA,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,SAAA;EACA,IAAA;EACA,YAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EACA,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,UAAA;IACE,IAAA;IACA,OAAA;IACA,SAAA;IACA,MAAA;IACA,KAAA;IACA,KAAA;IACA,KAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,SAAA,GAAY,WAAA;EACZ,OAAA;AAAA;AAAA,cA8BI,MAAA;EAAU,IAAA;EAAA,KAAA;EAAA,KAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,SAAA;EAAA,IAAA;EAAA,YAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAqBb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;UA2CiB,KAAA;EACf,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,QAAA;EACA,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,SAAA;EACA,IAAA;EACA,YAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EACA,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,UAAA;IACE,IAAA;IACA,OAAA;IACA,SAAA;IACA,MAAA;IACA,KAAA;IACA,KAAA;IACA,KAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,SAAA,GAAY,WAAA;EACZ,OAAA;AAAA;AAAA,cA8BI,MAAA;EAAU,IAAA;EAAA,KAAA;EAAA,KAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,SAAA;EAAA,IAAA;EAAA,YAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,SAAA;EAAA,UAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAqBb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -3,6 +3,7 @@
3
3
  import { cn, renderConditional } from "../../utils.mjs";
4
4
  import { drawer_exports } from "../../core/drawer.mjs";
5
5
  import Button from "../../Button.mjs";
6
+ import { DEFAULT_LOCALE, useConfig } from "../../providers/Config/context.mjs";
6
7
  import { X } from "lucide-react";
7
8
  import { useEffect } from "react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -38,6 +39,7 @@ const getSizeStyles = (direction, size) => {
38
39
  return direction === "top" || direction === "bottom" ? { height: value } : { width: value };
39
40
  };
40
41
  const Drawer = ({ open, title, extra, footer, closable = true, closeIcon, direction = "bottom", size = "medium", maskClosable = true, handlebar = true, draggable = false, rounded = false, mask = true, className, classNames, style, children, container, onClose, ...props }) => {
42
+ const { locale } = useConfig();
41
43
  useEffect(() => {
42
44
  if (!open || mask) return;
43
45
  const targetDocument = container?.ownerDocument ?? document;
@@ -95,7 +97,7 @@ const Drawer = ({ open, title, extra, footer, closable = true, closeIcon, direct
95
97
  type: "text",
96
98
  shape: "circle",
97
99
  size: "small",
98
- "aria-label": "닫기",
100
+ "aria-label": locale.close ?? DEFAULT_LOCALE.close,
99
101
  icon: closeIcon || /* @__PURE__ */ jsx(X, {}),
100
102
  onClick: onClose,
101
103
  className: cn(classNames?.close)
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.mjs","names":["drawer"],"sources":["../../../src/components/organisms/drawer.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\nimport { X } from 'lucide-react';\n\nimport { drawer } from '@repo/ui/core';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nconst {\n DrawerContent,\n Drawer: DrawerCore,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n} = drawer;\n\n// `body.style.pointerEvents` is global state (per document), so several\n// mask-less overlays opening at once would otherwise race: each instance\n// would capture whatever the previous one had already written and the\n// last cleanup would restore a stale value. Reference counting makes only\n// the first instance capture the original value and only the last one\n// restore it. Keyed by document (not a single module-level counter) so\n// drawers portaled into different documents — e.g. live-editor's iframe\n// Renderer — don't share state with the host document.\ntype MaskLessState = { count: number; originalPointerEvents: string | null };\nconst maskLessStates = new WeakMap<Document, MaskLessState>();\n\nconst getMaskLessState = (doc: Document): MaskLessState => {\n let state = maskLessStates.get(doc);\n\n if (!state) {\n state = { count: 0, originalPointerEvents: null };\n maskLessStates.set(doc, state);\n }\n\n return state;\n};\n\nexport interface Props {\n open: boolean;\n children?: React.ReactNode;\n title?: React.ReactNode;\n extra?: React.ReactNode;\n footer?: React.ReactNode;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n direction?: 'top' | 'bottom' | 'left' | 'right';\n size?: 'small' | 'medium' | 'large' | 'full' | string;\n maskClosable?: boolean;\n handlebar?: boolean;\n draggable?: boolean;\n rounded?: boolean;\n mask?: boolean;\n className?: string;\n style?: React.CSSProperties;\n classNames?: {\n mask?: string;\n content?: string;\n handlebar?: string;\n header?: string;\n title?: string;\n close?: string;\n extra?: string;\n body?: string;\n footer?: string;\n };\n container?: HTMLElement;\n onClose: () => void;\n}\n\nconst SIZES: Record<string, string> = {\n small: '30%',\n medium: '50%',\n large: '75%',\n full: '90%',\n};\n\n// Rounds the edge facing into the viewport — the opposite edge from\n// whichever side the drawer is anchored to.\nconst ROUNDED_CLASSES: Record<'top' | 'bottom' | 'left' | 'right', string> = {\n top: 'rounded-b-[30px]!',\n bottom: 'rounded-t-[30px]!',\n left: 'rounded-r-[30px]!',\n right: 'rounded-l-[30px]!',\n};\n\nconst getSizeStyles = (\n direction: 'top' | 'bottom' | 'left' | 'right',\n size: string,\n): React.CSSProperties => {\n const value = SIZES[size] || size;\n\n return direction === 'top' || direction === 'bottom'\n ? { height: value }\n : { width: value };\n};\n\nconst Drawer = ({\n open,\n title,\n extra,\n footer,\n closable = true,\n closeIcon,\n direction = 'bottom',\n size = 'medium',\n maskClosable = true,\n handlebar = true,\n draggable = false,\n rounded = false,\n mask = true,\n className,\n classNames,\n style,\n children,\n container,\n onClose,\n ...props\n}: Props) => {\n useEffect(() => {\n if (!open || mask) {\n return;\n }\n\n const targetDocument = container?.ownerDocument ?? document;\n const targetWindow = targetDocument.defaultView ?? window;\n const body = targetDocument.body;\n const state = getMaskLessState(targetDocument);\n\n if (state.count === 0) {\n state.originalPointerEvents = body.style.pointerEvents;\n }\n state.count += 1;\n\n const raf = targetWindow.requestAnimationFrame(() => {\n body.style.pointerEvents = 'auto';\n });\n\n return () => {\n targetWindow.cancelAnimationFrame(raf);\n state.count -= 1;\n\n if (state.count === 0) {\n body.style.pointerEvents = state.originalPointerEvents ?? '';\n state.originalPointerEvents = null;\n }\n };\n }, [open, mask, container]);\n\n return (\n <DrawerCore\n open={open}\n direction={direction}\n handleOnly={!draggable}\n container={container}\n onOpenChange={open => {\n if (!open) {\n onClose();\n }\n }}\n {...props}\n >\n <DrawerContent\n className={cn(\n 'border-none outline-none',\n rounded ? ROUNDED_CLASSES[direction] : 'rounded-none!',\n classNames?.content,\n className,\n //\n )}\n handlebar={handlebar}\n mask={mask}\n onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n classNames={{\n mask: classNames?.mask || '',\n handlebar: classNames?.handlebar || '',\n }}\n style={{\n ...getSizeStyles(direction, size),\n ...style,\n }}\n >\n <DrawerHeader\n className={cn(\n classNames?.header,\n !title && 'p-0',\n //\n )}\n >\n <div className=\"flex items-start gap-2\">\n {closable && (\n <Button\n type=\"text\"\n shape=\"circle\"\n size=\"small\"\n aria-label=\"닫기\"\n icon={closeIcon || <X />}\n onClick={onClose}\n className={cn(classNames?.close)}\n />\n )}\n <div className=\"flex flex-1 items-start justify-between gap-2\">\n <DrawerTitle className={cn(classNames?.title)}>\n {title}\n </DrawerTitle>\n {renderConditional(extra, v => (\n <div className={cn('shrink-0', classNames?.extra)}>{v}</div>\n ))}\n </div>\n </div>\n <DrawerDescription className=\"hidden\" />\n </DrawerHeader>\n <div\n className={cn(\n 'overflow-auto p-5',\n classNames?.body,\n //\n )}\n >\n {children}\n </div>\n {renderConditional(footer, v => (\n <DrawerFooter className={cn(classNames?.footer)}>{v}</DrawerFooter>\n ))}\n </DrawerContent>\n </DrawerCore>\n );\n};\n\nexport default Drawer;\n"],"mappings":";;;;;;;;;;AAWA,MAAM,EACJ,eACA,QAAQ,YACR,mBACA,cACA,cACA,gBACEA;AAWJ,MAAM,iCAAiB,IAAI,SAAkC;AAE7D,MAAM,oBAAoB,QAAiC;CACzD,IAAI,QAAQ,eAAe,IAAI,IAAI;AAEnC,KAAI,CAAC,OAAO;AACV,UAAQ;GAAE,OAAO;GAAG,uBAAuB;GAAM;AACjD,iBAAe,IAAI,KAAK,MAAM;;AAGhC,QAAO;;AAmCT,MAAM,QAAgC;CACpC,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACP;AAID,MAAM,kBAAuE;CAC3E,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AAED,MAAM,iBACJ,WACA,SACwB;CACxB,MAAM,QAAQ,MAAM,SAAS;AAE7B,QAAO,cAAc,SAAS,cAAc,WACxC,EAAE,QAAQ,OAAO,GACjB,EAAE,OAAO,OAAO;;AAGtB,MAAM,UAAU,EACd,MACA,OACA,OACA,QACA,WAAW,MACX,WACA,YAAY,UACZ,OAAO,UACP,eAAe,MACf,YAAY,MACZ,YAAY,OACZ,UAAU,OACV,OAAO,MACP,WACA,YACA,OACA,UACA,WACA,SACA,GAAG,YACQ;AACX,iBAAgB;AACd,MAAI,CAAC,QAAQ,KACX;EAGF,MAAM,iBAAiB,WAAW,iBAAiB;EACnD,MAAM,eAAe,eAAe,eAAe;EACnD,MAAM,OAAO,eAAe;EAC5B,MAAM,QAAQ,iBAAiB,eAAe;AAE9C,MAAI,MAAM,UAAU,EAClB,OAAM,wBAAwB,KAAK,MAAM;AAE3C,QAAM,SAAS;EAEf,MAAM,MAAM,aAAa,4BAA4B;AACnD,QAAK,MAAM,gBAAgB;IAC3B;AAEF,eAAa;AACX,gBAAa,qBAAqB,IAAI;AACtC,SAAM,SAAS;AAEf,OAAI,MAAM,UAAU,GAAG;AACrB,SAAK,MAAM,gBAAgB,MAAM,yBAAyB;AAC1D,UAAM,wBAAwB;;;IAGjC;EAAC;EAAM;EAAM;EAAU,CAAC;AAE3B,QACE,oBAAC;EACO;EACK;EACX,YAAY,CAAC;EACF;EACX,eAAc,SAAQ;AACpB,OAAI,CAAC,KACH,UAAS;;EAGb,GAAI;YAEJ,qBAAC;GACC,WAAW,GACT,4BACA,UAAU,gBAAgB,aAAa,iBACvC,YAAY,SACZ,UAED;GACU;GACL;GACN,uBAAsB,UAAS;AAC7B,QAAI,CAAC,aACH,OAAM,gBAAgB;;GAG1B,YAAY;IACV,MAAM,YAAY,QAAQ;IAC1B,WAAW,YAAY,aAAa;IACrC;GACD,OAAO;IACL,GAAG,cAAc,WAAW,KAAK;IACjC,GAAG;IACJ;;IAED,qBAAC;KACC,WAAW,GACT,YAAY,QACZ,CAAC,SAAS,MAEX;gBAED,qBAAC;MAAI,WAAU;iBACZ,YACC,oBAAC;OACC,MAAK;OACL,OAAM;OACN,MAAK;OACL,cAAW;OACX,MAAM,aAAa,oBAAC,MAAI;OACxB,SAAS;OACT,WAAW,GAAG,YAAY,MAAM;QAChC,EAEJ,qBAAC;OAAI,WAAU;kBACb,oBAAC;QAAY,WAAW,GAAG,YAAY,MAAM;kBAC1C;SACW,EACb,kBAAkB,QAAO,MACxB,oBAAC;QAAI,WAAW,GAAG,YAAY,YAAY,MAAM;kBAAG;SAAQ,CAC5D;QACE;OACF,EACN,oBAAC,qBAAkB,WAAU,WAAW;MAC3B;IACf,oBAAC;KACC,WAAW,GACT,qBACA,YAAY,KAEb;KAEA;MACG;IACL,kBAAkB,SAAQ,MACzB,oBAAC;KAAa,WAAW,GAAG,YAAY,OAAO;eAAG;MAAiB,CACnE;;IACY;GACL"}
1
+ {"version":3,"file":"drawer.mjs","names":["drawer"],"sources":["../../../src/components/organisms/drawer.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\nimport { X } from 'lucide-react';\n\nimport { drawer } from '@repo/ui/core';\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nconst {\n DrawerContent,\n Drawer: DrawerCore,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n} = drawer;\n\n// `body.style.pointerEvents` is global state (per document), so several\n// mask-less overlays opening at once would otherwise race: each instance\n// would capture whatever the previous one had already written and the\n// last cleanup would restore a stale value. Reference counting makes only\n// the first instance capture the original value and only the last one\n// restore it. Keyed by document (not a single module-level counter) so\n// drawers portaled into different documents — e.g. live-editor's iframe\n// Renderer — don't share state with the host document.\ntype MaskLessState = { count: number; originalPointerEvents: string | null };\nconst maskLessStates = new WeakMap<Document, MaskLessState>();\n\nconst getMaskLessState = (doc: Document): MaskLessState => {\n let state = maskLessStates.get(doc);\n\n if (!state) {\n state = { count: 0, originalPointerEvents: null };\n maskLessStates.set(doc, state);\n }\n\n return state;\n};\n\nexport interface Props {\n open: boolean;\n children?: React.ReactNode;\n title?: React.ReactNode;\n extra?: React.ReactNode;\n footer?: React.ReactNode;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n direction?: 'top' | 'bottom' | 'left' | 'right';\n size?: 'small' | 'medium' | 'large' | 'full' | string;\n maskClosable?: boolean;\n handlebar?: boolean;\n draggable?: boolean;\n rounded?: boolean;\n mask?: boolean;\n className?: string;\n style?: React.CSSProperties;\n classNames?: {\n mask?: string;\n content?: string;\n handlebar?: string;\n header?: string;\n title?: string;\n close?: string;\n extra?: string;\n body?: string;\n footer?: string;\n };\n container?: HTMLElement;\n onClose: () => void;\n}\n\nconst SIZES: Record<string, string> = {\n small: '30%',\n medium: '50%',\n large: '75%',\n full: '90%',\n};\n\n// Rounds the edge facing into the viewport — the opposite edge from\n// whichever side the drawer is anchored to.\nconst ROUNDED_CLASSES: Record<'top' | 'bottom' | 'left' | 'right', string> = {\n top: 'rounded-b-[30px]!',\n bottom: 'rounded-t-[30px]!',\n left: 'rounded-r-[30px]!',\n right: 'rounded-l-[30px]!',\n};\n\nconst getSizeStyles = (\n direction: 'top' | 'bottom' | 'left' | 'right',\n size: string,\n): React.CSSProperties => {\n const value = SIZES[size] || size;\n\n return direction === 'top' || direction === 'bottom'\n ? { height: value }\n : { width: value };\n};\n\nconst Drawer = ({\n open,\n title,\n extra,\n footer,\n closable = true,\n closeIcon,\n direction = 'bottom',\n size = 'medium',\n maskClosable = true,\n handlebar = true,\n draggable = false,\n rounded = false,\n mask = true,\n className,\n classNames,\n style,\n children,\n container,\n onClose,\n ...props\n}: Props) => {\n const { locale } = useConfig();\n\n useEffect(() => {\n if (!open || mask) {\n return;\n }\n\n const targetDocument = container?.ownerDocument ?? document;\n const targetWindow = targetDocument.defaultView ?? window;\n const body = targetDocument.body;\n const state = getMaskLessState(targetDocument);\n\n if (state.count === 0) {\n state.originalPointerEvents = body.style.pointerEvents;\n }\n state.count += 1;\n\n const raf = targetWindow.requestAnimationFrame(() => {\n body.style.pointerEvents = 'auto';\n });\n\n return () => {\n targetWindow.cancelAnimationFrame(raf);\n state.count -= 1;\n\n if (state.count === 0) {\n body.style.pointerEvents = state.originalPointerEvents ?? '';\n state.originalPointerEvents = null;\n }\n };\n }, [open, mask, container]);\n\n return (\n <DrawerCore\n open={open}\n direction={direction}\n handleOnly={!draggable}\n container={container}\n onOpenChange={open => {\n if (!open) {\n onClose();\n }\n }}\n {...props}\n >\n <DrawerContent\n className={cn(\n 'border-none outline-none',\n rounded ? ROUNDED_CLASSES[direction] : 'rounded-none!',\n classNames?.content,\n className,\n //\n )}\n handlebar={handlebar}\n mask={mask}\n onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n classNames={{\n mask: classNames?.mask || '',\n handlebar: classNames?.handlebar || '',\n }}\n style={{\n ...getSizeStyles(direction, size),\n ...style,\n }}\n >\n <DrawerHeader\n className={cn(\n classNames?.header,\n !title && 'p-0',\n //\n )}\n >\n <div className=\"flex items-start gap-2\">\n {closable && (\n <Button\n type=\"text\"\n shape=\"circle\"\n size=\"small\"\n aria-label={locale.close ?? DEFAULT_LOCALE.close}\n icon={closeIcon || <X />}\n onClick={onClose}\n className={cn(classNames?.close)}\n />\n )}\n <div className=\"flex flex-1 items-start justify-between gap-2\">\n <DrawerTitle className={cn(classNames?.title)}>\n {title}\n </DrawerTitle>\n {renderConditional(extra, v => (\n <div className={cn('shrink-0', classNames?.extra)}>{v}</div>\n ))}\n </div>\n </div>\n <DrawerDescription className=\"hidden\" />\n </DrawerHeader>\n <div\n className={cn(\n 'overflow-auto p-5',\n classNames?.body,\n //\n )}\n >\n {children}\n </div>\n {renderConditional(footer, v => (\n <DrawerFooter className={cn(classNames?.footer)}>{v}</DrawerFooter>\n ))}\n </DrawerContent>\n </DrawerCore>\n );\n};\n\nexport default Drawer;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,EACJ,eACA,QAAQ,YACR,mBACA,cACA,cACA,gBACEA;AAWJ,MAAM,iCAAiB,IAAI,SAAkC;AAE7D,MAAM,oBAAoB,QAAiC;CACzD,IAAI,QAAQ,eAAe,IAAI,IAAI;AAEnC,KAAI,CAAC,OAAO;AACV,UAAQ;GAAE,OAAO;GAAG,uBAAuB;GAAM;AACjD,iBAAe,IAAI,KAAK,MAAM;;AAGhC,QAAO;;AAmCT,MAAM,QAAgC;CACpC,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACP;AAID,MAAM,kBAAuE;CAC3E,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACR;AAED,MAAM,iBACJ,WACA,SACwB;CACxB,MAAM,QAAQ,MAAM,SAAS;AAE7B,QAAO,cAAc,SAAS,cAAc,WACxC,EAAE,QAAQ,OAAO,GACjB,EAAE,OAAO,OAAO;;AAGtB,MAAM,UAAU,EACd,MACA,OACA,OACA,QACA,WAAW,MACX,WACA,YAAY,UACZ,OAAO,UACP,eAAe,MACf,YAAY,MACZ,YAAY,OACZ,UAAU,OACV,OAAO,MACP,WACA,YACA,OACA,UACA,WACA,SACA,GAAG,YACQ;CACX,MAAM,EAAE,WAAW,WAAW;AAE9B,iBAAgB;AACd,MAAI,CAAC,QAAQ,KACX;EAGF,MAAM,iBAAiB,WAAW,iBAAiB;EACnD,MAAM,eAAe,eAAe,eAAe;EACnD,MAAM,OAAO,eAAe;EAC5B,MAAM,QAAQ,iBAAiB,eAAe;AAE9C,MAAI,MAAM,UAAU,EAClB,OAAM,wBAAwB,KAAK,MAAM;AAE3C,QAAM,SAAS;EAEf,MAAM,MAAM,aAAa,4BAA4B;AACnD,QAAK,MAAM,gBAAgB;IAC3B;AAEF,eAAa;AACX,gBAAa,qBAAqB,IAAI;AACtC,SAAM,SAAS;AAEf,OAAI,MAAM,UAAU,GAAG;AACrB,SAAK,MAAM,gBAAgB,MAAM,yBAAyB;AAC1D,UAAM,wBAAwB;;;IAGjC;EAAC;EAAM;EAAM;EAAU,CAAC;AAE3B,QACE,oBAAC;EACO;EACK;EACX,YAAY,CAAC;EACF;EACX,eAAc,SAAQ;AACpB,OAAI,CAAC,KACH,UAAS;;EAGb,GAAI;YAEJ,qBAAC;GACC,WAAW,GACT,4BACA,UAAU,gBAAgB,aAAa,iBACvC,YAAY,SACZ,UAED;GACU;GACL;GACN,uBAAsB,UAAS;AAC7B,QAAI,CAAC,aACH,OAAM,gBAAgB;;GAG1B,YAAY;IACV,MAAM,YAAY,QAAQ;IAC1B,WAAW,YAAY,aAAa;IACrC;GACD,OAAO;IACL,GAAG,cAAc,WAAW,KAAK;IACjC,GAAG;IACJ;;IAED,qBAAC;KACC,WAAW,GACT,YAAY,QACZ,CAAC,SAAS,MAEX;gBAED,qBAAC;MAAI,WAAU;iBACZ,YACC,oBAAC;OACC,MAAK;OACL,OAAM;OACN,MAAK;OACL,cAAY,OAAO,SAAS,eAAe;OAC3C,MAAM,aAAa,oBAAC,MAAI;OACxB,SAAS;OACT,WAAW,GAAG,YAAY,MAAM;QAChC,EAEJ,qBAAC;OAAI,WAAU;kBACb,oBAAC;QAAY,WAAW,GAAG,YAAY,MAAM;kBAC1C;SACW,EACb,kBAAkB,QAAO,MACxB,oBAAC;QAAI,WAAW,GAAG,YAAY,YAAY,MAAM;kBAAG;SAAQ,CAC5D;QACE;OACF,EACN,oBAAC,qBAAkB,WAAU,WAAW;MAC3B;IACf,oBAAC;KACC,WAAW,GACT,qBACA,YAAY,KAEb;KAEA;MACG;IACL,kBAAkB,SAAQ,MACzB,oBAAC;KAAa,WAAW,GAAG,YAAY,OAAO;eAAG;MAAiB,CACnE;;IACY;GACL"}
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
5
+ import { v4 } from "uuid";
6
+ import { createRoot } from "react-dom/client";
7
+
8
+ //#region src/components/organisms/imperative-stack.tsx
9
+ const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
10
+ function createImperativeStack({ createRootElement, StackItem }) {
11
+ const containerStates = /* @__PURE__ */ new Map();
12
+ const rootElements = /* @__PURE__ */ new WeakMap();
13
+ const reactRoots = /* @__PURE__ */ new Map();
14
+ const getContainerState = (container) => {
15
+ let state = containerStates.get(container);
16
+ if (!state) {
17
+ state = {
18
+ stack: [],
19
+ update: null
20
+ };
21
+ containerStates.set(container, state);
22
+ }
23
+ return state;
24
+ };
25
+ const getRootElement = (container) => {
26
+ if (!isBrowser) return null;
27
+ const targetContainer = container || document.body;
28
+ let rootEl = rootElements.get(targetContainer);
29
+ if (!rootEl) {
30
+ rootEl = createRootElement();
31
+ targetContainer.appendChild(rootEl);
32
+ rootElements.set(targetContainer, rootEl);
33
+ }
34
+ return rootEl;
35
+ };
36
+ const StackRenderer = ({ container }) => {
37
+ const [, forceUpdate] = useState({});
38
+ useEffect(() => {
39
+ const state = getContainerState(container);
40
+ state.update = () => forceUpdate({});
41
+ return () => {
42
+ state.update = null;
43
+ };
44
+ }, [container]);
45
+ const { stack } = getContainerState(container);
46
+ return /* @__PURE__ */ jsx(Fragment$1, { children: stack.map(({ id, ...props }) => /* @__PURE__ */ jsx(StackItem, {
47
+ id,
48
+ ...props
49
+ }, id)) });
50
+ };
51
+ const render = (props) => {
52
+ if (!isBrowser) return;
53
+ const targetContainer = props.container || document.body;
54
+ const rootElement = getRootElement(targetContainer);
55
+ if (!reactRoots.has(targetContainer)) {
56
+ const root = createRoot(rootElement);
57
+ reactRoots.set(targetContainer, root);
58
+ root.render(/* @__PURE__ */ jsx(StackRenderer, { container: targetContainer }));
59
+ }
60
+ const state = getContainerState(targetContainer);
61
+ const id = props.id || v4();
62
+ state.stack.push({
63
+ ...props,
64
+ id
65
+ });
66
+ state.update?.();
67
+ return id;
68
+ };
69
+ const destroy = (id) => {
70
+ if (!id) {
71
+ containerStates.forEach((state) => {
72
+ state.stack = [];
73
+ state.update?.();
74
+ });
75
+ reactRoots.forEach((root, container) => {
76
+ root.unmount();
77
+ rootElements.get(container)?.remove();
78
+ rootElements.delete(container);
79
+ });
80
+ reactRoots.clear();
81
+ containerStates.clear();
82
+ return;
83
+ }
84
+ containerStates.forEach((state, container) => {
85
+ if (!state.stack.some((item) => item.id === id)) return;
86
+ state.stack = state.stack.filter((item) => item.id !== id);
87
+ state.update?.();
88
+ if (!state.stack.length) {
89
+ reactRoots.get(container)?.unmount();
90
+ reactRoots.delete(container);
91
+ containerStates.delete(container);
92
+ rootElements.get(container)?.remove();
93
+ rootElements.delete(container);
94
+ }
95
+ });
96
+ };
97
+ return {
98
+ render,
99
+ destroy,
100
+ getRootElement
101
+ };
102
+ }
103
+
104
+ //#endregion
105
+ export { createImperativeStack, isBrowser };
106
+ //# sourceMappingURL=imperative-stack.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imperative-stack.mjs","names":["uuid"],"sources":["../../../src/components/organisms/imperative-stack.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport { v4 as uuid } from 'uuid';\n\n// Shared machinery behind Modal.info/success/error/warning/confirm and\n// Toast.info/success/error/warning — both used to independently\n// reimplement ~120 near-identical lines of this (container-scoped stack,\n// a React root per container, imperative render/destroy). The only parts\n// that actually differ between the two are the DOM node their stack\n// mounts into (position/ARIA) and which component renders each stack\n// entry — everything else here is generic over that.\n\nexport const isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState<TProps> = {\n stack: (TProps & { id: string })[];\n update: (() => void) | null;\n};\n\nexport interface ImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n render: (props: TProps) => string | undefined;\n destroy: (id?: string) => void;\n getRootElement: (container?: HTMLElement) => HTMLElement | null;\n}\n\nexport interface ImperativeStackOptions<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n /** Creates the DOM node this stack's React root mounts into — not yet\n * attached to the document; the factory appends it to the target\n * container itself. Called once per distinct container. */\n createRootElement: () => HTMLElement;\n /** Renders one stack entry — typically each caller's \"Static<Thing>\"\n * component, which owns its own createPortal(..., getRootElement()). */\n StackItem: React.ComponentType<TProps & { id: string }>;\n}\n\nexport function createImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n>({\n createRootElement,\n StackItem,\n}: ImperativeStackOptions<TProps>): ImperativeStack<TProps> {\n const containerStates = new Map<HTMLElement, ContainerState<TProps>>();\n const rootElements = new WeakMap<HTMLElement, HTMLElement>();\n const reactRoots = new Map<HTMLElement, Root>();\n\n const getContainerState = (\n container: HTMLElement,\n ): ContainerState<TProps> => {\n let state = containerStates.get(container);\n\n if (!state) {\n state = { stack: [], update: null };\n containerStates.set(container, state);\n }\n\n return state;\n };\n\n const getRootElement = (container?: HTMLElement): HTMLElement | null => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = rootElements.get(targetContainer);\n\n if (!rootEl) {\n rootEl = createRootElement();\n targetContainer.appendChild(rootEl);\n rootElements.set(targetContainer, rootEl);\n }\n\n return rootEl;\n };\n\n const StackRenderer = ({ container }: { container: HTMLElement }) => {\n const [, forceUpdate] = useState({});\n\n useEffect(() => {\n const state = getContainerState(container);\n state.update = () => forceUpdate({});\n return () => {\n state.update = null;\n };\n }, [container]);\n\n const { stack } = getContainerState(container);\n\n return (\n <>\n {stack.map(({ id, ...props }) => (\n <StackItem key={id} id={id} {...(props as TProps)} />\n ))}\n </>\n );\n };\n\n const render = (props: TProps): string | undefined => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = getRootElement(targetContainer)!;\n\n if (!reactRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n reactRoots.set(targetContainer, root);\n root.render(<StackRenderer container={targetContainer} />);\n }\n\n const state = getContainerState(targetContainer);\n const id = props.id || uuid();\n state.stack.push({ ...props, id });\n state.update?.();\n\n return id;\n };\n\n const destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n reactRoots.forEach((root, container) => {\n root.unmount();\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n });\n reactRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(item => item.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(item => item.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n reactRoots.get(container)?.unmount();\n reactRoots.delete(container);\n containerStates.delete(container);\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n }\n });\n };\n\n return { render, destroy, getRootElement };\n}\n"],"mappings":";;;;;;;;AAeA,MAAa,YACX,OAAO,WAAW,eAAe,OAAO,aAAa;AA2BvD,SAAgB,sBAEd,EACA,mBACA,aAC0D;CAC1D,MAAM,kCAAkB,IAAI,KAA0C;CACtE,MAAM,+BAAe,IAAI,SAAmC;CAC5D,MAAM,6BAAa,IAAI,KAAwB;CAE/C,MAAM,qBACJ,cAC2B;EAC3B,IAAI,QAAQ,gBAAgB,IAAI,UAAU;AAE1C,MAAI,CAAC,OAAO;AACV,WAAQ;IAAE,OAAO,EAAE;IAAE,QAAQ;IAAM;AACnC,mBAAgB,IAAI,WAAW,MAAM;;AAGvC,SAAO;;CAGT,MAAM,kBAAkB,cAAgD;AACtE,MAAI,CAAC,UACH,QAAO;EAGT,MAAM,kBAAkB,aAAa,SAAS;EAC9C,IAAI,SAAS,aAAa,IAAI,gBAAgB;AAE9C,MAAI,CAAC,QAAQ;AACX,YAAS,mBAAmB;AAC5B,mBAAgB,YAAY,OAAO;AACnC,gBAAa,IAAI,iBAAiB,OAAO;;AAG3C,SAAO;;CAGT,MAAM,iBAAiB,EAAE,gBAA4C;EACnE,MAAM,GAAG,eAAe,SAAS,EAAE,CAAC;AAEpC,kBAAgB;GACd,MAAM,QAAQ,kBAAkB,UAAU;AAC1C,SAAM,eAAe,YAAY,EAAE,CAAC;AACpC,gBAAa;AACX,UAAM,SAAS;;KAEhB,CAAC,UAAU,CAAC;EAEf,MAAM,EAAE,UAAU,kBAAkB,UAAU;AAE9C,SACE,4CACG,MAAM,KAAK,EAAE,IAAI,GAAG,YACnB,oBAAC;GAAuB;GAAI,GAAK;KAAjB,GAAqC,CACrD,GACD;;CAIP,MAAM,UAAU,UAAsC;AACpD,MAAI,CAAC,UACH;EAGF,MAAM,kBAAkB,MAAM,aAAa,SAAS;EACpD,MAAM,cAAc,eAAe,gBAAgB;AAEnD,MAAI,CAAC,WAAW,IAAI,gBAAgB,EAAE;GACpC,MAAM,OAAO,WAAW,YAAY;AACpC,cAAW,IAAI,iBAAiB,KAAK;AACrC,QAAK,OAAO,oBAAC,iBAAc,WAAW,kBAAmB,CAAC;;EAG5D,MAAM,QAAQ,kBAAkB,gBAAgB;EAChD,MAAM,KAAK,MAAM,MAAMA,IAAM;AAC7B,QAAM,MAAM,KAAK;GAAE,GAAG;GAAO;GAAI,CAAC;AAClC,QAAM,UAAU;AAEhB,SAAO;;CAGT,MAAM,WAAW,OAAgB;AAC/B,MAAI,CAAC,IAAI;AACP,mBAAgB,SAAQ,UAAS;AAC/B,UAAM,QAAQ,EAAE;AAChB,UAAM,UAAU;KAChB;AACF,cAAW,SAAS,MAAM,cAAc;AACtC,SAAK,SAAS;AACd,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;KAC9B;AACF,cAAW,OAAO;AAClB,mBAAgB,OAAO;AACvB;;AAGF,kBAAgB,SAAS,OAAO,cAAc;AAC5C,OAAI,CAAC,MAAM,MAAM,MAAK,SAAQ,KAAK,OAAO,GAAG,CAC3C;AAGF,SAAM,QAAQ,MAAM,MAAM,QAAO,SAAQ,KAAK,OAAO,GAAG;AACxD,SAAM,UAAU;AAEhB,OAAI,CAAC,MAAM,MAAM,QAAQ;AACvB,eAAW,IAAI,UAAU,EAAE,SAAS;AACpC,eAAW,OAAO,UAAU;AAC5B,oBAAgB,OAAO,UAAU;AACjC,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;;IAEhC;;AAGJ,QAAO;EAAE;EAAQ;EAAS;EAAgB"}
@@ -1,5 +1,7 @@
1
1
  import { Drawer, Props } from "./drawer.mjs";
2
+ import { Props as Props$1 } from "./list/list.mjs";
2
3
  import { List } from "./list/index.mjs";
3
- import { Modal } from "./modal.mjs";
4
+ import { Modal, Props as Props$2 } from "./modal.mjs";
5
+ import { Props as Props$3 } from "./swiper/swiper.mjs";
4
6
  import { Swiper } from "./swiper/index.mjs";
5
7
  import { StaticProps, Toast } from "./toast.mjs";
@@ -1,5 +1,5 @@
1
1
  import { Item } from "./item.mjs";
2
- import { List as List$1 } from "./list.mjs";
2
+ import { List as List$1, Props } from "./list.mjs";
3
3
 
4
4
  //#region src/components/organisms/list/index.d.ts
5
5
  type ListComponent = typeof List$1 & {