@jbpark/ui-kit 10.0.1 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +40 -25
- package/README.md +40 -25
- package/dist/Breadcrumb.d.mts +39 -0
- package/dist/Breadcrumb.d.mts.map +1 -0
- package/dist/Breadcrumb.mjs +103 -0
- package/dist/Breadcrumb.mjs.map +1 -0
- package/dist/Pagination.d.mts +53 -0
- package/dist/Pagination.d.mts.map +1 -0
- package/dist/Pagination.mjs +208 -0
- package/dist/Pagination.mjs.map +1 -0
- package/dist/Table.d.mts +48 -0
- package/dist/Table.d.mts.map +1 -0
- package/dist/Table.mjs +119 -0
- package/dist/Table.mjs.map +1 -0
- package/dist/components/atoms/checkbox/checkbox.mjs +2 -1
- package/dist/components/atoms/checkbox/checkbox.mjs.map +1 -1
- package/dist/components/atoms/checkbox/group.mjs +2 -1
- package/dist/components/atoms/checkbox/group.mjs.map +1 -1
- package/dist/components/atoms/color-picker.mjs +1 -1
- package/dist/components/atoms/date-picker.mjs +1 -1
- package/dist/components/atoms/float-button/back-top.mjs +1 -1
- package/dist/components/atoms/index.d.mts +2 -1
- package/dist/components/atoms/input/search.mjs +3 -1
- package/dist/components/atoms/input/search.mjs.map +1 -1
- package/dist/components/atoms/popover.mjs +1 -1
- package/dist/components/atoms/radio/group.mjs +1 -1
- package/dist/components/atoms/radio/radio.mjs +2 -1
- package/dist/components/atoms/radio/radio.mjs.map +1 -1
- package/dist/components/atoms/select-multiple.d.mts +29 -0
- package/dist/components/atoms/select-multiple.d.mts.map +1 -0
- package/dist/components/atoms/select-multiple.mjs +97 -0
- package/dist/components/atoms/select-multiple.mjs.map +1 -0
- package/dist/components/atoms/select-searchable-options.d.mts +21 -0
- package/dist/components/atoms/select-searchable-options.d.mts.map +1 -0
- package/dist/components/atoms/select-searchable-options.mjs +62 -0
- package/dist/components/atoms/select-searchable-options.mjs.map +1 -0
- package/dist/components/atoms/select-searchable.d.mts +22 -0
- package/dist/components/atoms/select-searchable.d.mts.map +1 -0
- package/dist/components/atoms/select-searchable.mjs +65 -0
- package/dist/components/atoms/select-searchable.mjs.map +1 -0
- package/dist/components/atoms/select.d.mts +8 -2
- package/dist/components/atoms/select.d.mts.map +1 -1
- package/dist/components/atoms/select.mjs +11 -1
- package/dist/components/atoms/select.mjs.map +1 -1
- package/dist/components/atoms/slider/slider.mjs +1 -1
- package/dist/components/atoms/switch.mjs +1 -1
- package/dist/components/atoms/tooltip.d.mts +21 -0
- package/dist/components/atoms/tooltip.d.mts.map +1 -0
- package/dist/components/atoms/tooltip.mjs +78 -0
- package/dist/components/atoms/tooltip.mjs.map +1 -0
- package/dist/components/atoms/typography/paragraph.mjs +1 -0
- package/dist/components/atoms/typography/paragraph.mjs.map +1 -1
- package/dist/components/atoms/typography/title.mjs +1 -0
- package/dist/components/atoms/typography/title.mjs.map +1 -1
- package/dist/components/molecules/dropdown.mjs +1 -1
- package/dist/components/molecules/index.d.mts +13 -10
- package/dist/components/molecules/marquees/marquees.mjs +1 -1
- package/dist/components/molecules/menu/menu.mjs +2 -1
- package/dist/components/molecules/menu/menu.mjs.map +1 -1
- package/dist/components/molecules/tabs.d.mts +37 -0
- package/dist/components/molecules/tabs.d.mts.map +1 -0
- package/dist/components/molecules/tabs.mjs +51 -0
- package/dist/components/molecules/tabs.mjs.map +1 -0
- package/dist/components/molecules/upload.mjs +2 -1
- package/dist/components/molecules/upload.mjs.map +1 -1
- package/dist/components/organisms/drawer.d.mts.map +1 -1
- package/dist/components/organisms/drawer.mjs +7 -2
- package/dist/components/organisms/drawer.mjs.map +1 -1
- package/dist/components/organisms/index.d.mts +6 -5
- package/dist/components/organisms/list/list.mjs +1 -1
- package/dist/components/organisms/modal.d.mts.map +1 -1
- package/dist/components/organisms/modal.mjs +7 -4
- package/dist/components/organisms/modal.mjs.map +1 -1
- package/dist/components/organisms/toast.d.mts.map +1 -1
- package/dist/components/organisms/toast.mjs +2 -1
- package/dist/components/organisms/toast.mjs.map +1 -1
- package/dist/components/templates/empty.mjs +1 -0
- package/dist/components/templates/empty.mjs.map +1 -1
- package/dist/components/templates/layout/content.mjs +1 -0
- package/dist/components/templates/layout/content.mjs.map +1 -1
- package/dist/components/templates/layout/footer.mjs +1 -0
- package/dist/components/templates/layout/footer.mjs.map +1 -1
- package/dist/components/templates/layout/header.mjs +1 -0
- package/dist/components/templates/layout/header.mjs.map +1 -1
- package/dist/components/templates/layout/layout.mjs +1 -0
- package/dist/components/templates/layout/layout.mjs.map +1 -1
- package/dist/components/templates/layout/sider.mjs +3 -1
- package/dist/components/templates/layout/sider.mjs.map +1 -1
- package/dist/components/templates/page-header.mjs +1 -0
- package/dist/components/templates/page-header.mjs.map +1 -1
- package/dist/components/templates/result.mjs +1 -0
- package/dist/components/templates/result.mjs.map +1 -1
- package/dist/core/badge.d.mts +1 -1
- package/dist/core/button.d.mts +1 -1
- package/dist/core/combobox.d.mts +7 -0
- package/dist/core/combobox.d.mts.map +1 -0
- package/dist/core/combobox.mjs +99 -0
- package/dist/core/combobox.mjs.map +1 -0
- package/dist/core/dialog.mjs.map +1 -1
- package/dist/core/drawer.mjs.map +1 -1
- package/dist/core/field.mjs +2 -4
- package/dist/core/field.mjs.map +1 -1
- package/dist/core/index.d.mts +4 -1
- package/dist/core/select.mjs +27 -22
- package/dist/core/select.mjs.map +1 -1
- package/dist/core/tabs.d.mts +9 -0
- package/dist/core/tabs.d.mts.map +1 -0
- package/dist/core/tabs.mjs +59 -0
- package/dist/core/tabs.mjs.map +1 -0
- package/dist/core/tooltip.d.mts +2 -0
- package/dist/core/tooltip.mjs +41 -0
- package/dist/core/tooltip.mjs.map +1 -0
- package/dist/index.d.mts +31 -26
- package/dist/index.mjs +7 -2
- package/dist/lib/z-layers.mjs +21 -0
- package/dist/lib/z-layers.mjs.map +1 -1
- package/dist/providers/config/dark-mode.mjs +2 -10
- package/dist/providers/config/dark-mode.mjs.map +1 -1
- package/dist/style.css +195 -16
- package/package.json +17 -2
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { tooltip_exports } from "../../core/tooltip.mjs";
|
|
3
|
+
import { Children } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/atoms/tooltip.tsx
|
|
6
|
+
const { Tooltip: Core, TooltipContent, TooltipTrigger } = tooltip_exports;
|
|
7
|
+
const placementMap = {
|
|
8
|
+
top: {
|
|
9
|
+
side: "top",
|
|
10
|
+
align: "center"
|
|
11
|
+
},
|
|
12
|
+
left: {
|
|
13
|
+
side: "left",
|
|
14
|
+
align: "center"
|
|
15
|
+
},
|
|
16
|
+
right: {
|
|
17
|
+
side: "right",
|
|
18
|
+
align: "center"
|
|
19
|
+
},
|
|
20
|
+
bottom: {
|
|
21
|
+
side: "bottom",
|
|
22
|
+
align: "center"
|
|
23
|
+
},
|
|
24
|
+
topLeft: {
|
|
25
|
+
side: "top",
|
|
26
|
+
align: "start"
|
|
27
|
+
},
|
|
28
|
+
topRight: {
|
|
29
|
+
side: "top",
|
|
30
|
+
align: "end"
|
|
31
|
+
},
|
|
32
|
+
bottomLeft: {
|
|
33
|
+
side: "bottom",
|
|
34
|
+
align: "start"
|
|
35
|
+
},
|
|
36
|
+
bottomRight: {
|
|
37
|
+
side: "bottom",
|
|
38
|
+
align: "end"
|
|
39
|
+
},
|
|
40
|
+
leftTop: {
|
|
41
|
+
side: "left",
|
|
42
|
+
align: "start"
|
|
43
|
+
},
|
|
44
|
+
leftBottom: {
|
|
45
|
+
side: "left",
|
|
46
|
+
align: "end"
|
|
47
|
+
},
|
|
48
|
+
rightTop: {
|
|
49
|
+
side: "right",
|
|
50
|
+
align: "start"
|
|
51
|
+
},
|
|
52
|
+
rightBottom: {
|
|
53
|
+
side: "right",
|
|
54
|
+
align: "end"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const Tooltip = ({ children, content, className, placement = "top", offset = 8, delay, closeDelay, ...props }) => {
|
|
58
|
+
const trigger = Children.only(children);
|
|
59
|
+
const { side, align } = placementMap[placement];
|
|
60
|
+
return /* @__PURE__ */ jsxs(Core, {
|
|
61
|
+
...props,
|
|
62
|
+
children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
63
|
+
render: trigger,
|
|
64
|
+
delay,
|
|
65
|
+
closeDelay
|
|
66
|
+
}), /* @__PURE__ */ jsx(TooltipContent, {
|
|
67
|
+
side,
|
|
68
|
+
align,
|
|
69
|
+
sideOffset: offset,
|
|
70
|
+
className,
|
|
71
|
+
children: content
|
|
72
|
+
})]
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { Tooltip as default };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=tooltip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.mjs","names":["tooltip"],"sources":["../../../src/components/atoms/tooltip.tsx"],"sourcesContent":["'use client';\n\nimport { Children, type ReactElement, type ReactNode } from 'react';\n\nimport { tooltip } from '../../core';\n\nconst { Tooltip: Core, TooltipContent, TooltipTrigger } = tooltip;\n\ntype Placement =\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n\ntype Side = NonNullable<React.ComponentProps<typeof TooltipContent>['side']>;\ntype Align = NonNullable<React.ComponentProps<typeof TooltipContent>['align']>;\n\nconst placementMap: Record<Placement, { side: Side; align: Align }> = {\n top: { side: 'top', align: 'center' },\n left: { side: 'left', align: 'center' },\n right: { side: 'right', align: 'center' },\n bottom: { side: 'bottom', align: 'center' },\n topLeft: { side: 'top', align: 'start' },\n topRight: { side: 'top', align: 'end' },\n bottomLeft: { side: 'bottom', align: 'start' },\n bottomRight: { side: 'bottom', align: 'end' },\n leftTop: { side: 'left', align: 'start' },\n leftBottom: { side: 'left', align: 'end' },\n rightTop: { side: 'right', align: 'start' },\n rightBottom: { side: 'right', align: 'end' },\n};\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'children' | 'handle' | 'triggerId' | 'defaultTriggerId'\n> {\n children: ReactElement;\n /** Supplementary visual hint; keep essential information visible elsewhere. */\n content: ReactNode;\n /** Popup class; the child retains its own className. */\n className?: string;\n placement?: Placement;\n /** Distance between the trigger and popup in pixels. */\n offset?: number;\n /** Hover delay in milliseconds. Keyboard focus opens without this delay. */\n delay?: number;\n closeDelay?: number;\n}\n\nconst Tooltip = ({\n children,\n content,\n className,\n placement = 'top',\n offset = 8,\n delay,\n closeDelay,\n ...props\n}: Props) => {\n const trigger = Children.only(children);\n const { side, align } = placementMap[placement];\n\n return (\n <Core {...props}>\n <TooltipTrigger render={trigger} delay={delay} closeDelay={closeDelay} />\n <TooltipContent\n side={side}\n align={align}\n sideOffset={offset}\n className={className}\n >\n {content}\n </TooltipContent>\n </Core>\n );\n};\n\nexport default Tooltip;\n"],"mappings":";;;;;AAMA,MAAM,EAAE,SAAS,MAAM,gBAAgB,mBAAmBA;AAmB1D,MAAM,eAAgE;CACpE,KAAK;EAAE,MAAM;EAAO,OAAO;CAAS;CACpC,MAAM;EAAE,MAAM;EAAQ,OAAO;CAAS;CACtC,OAAO;EAAE,MAAM;EAAS,OAAO;CAAS;CACxC,QAAQ;EAAE,MAAM;EAAU,OAAO;CAAS;CAC1C,SAAS;EAAE,MAAM;EAAO,OAAO;CAAQ;CACvC,UAAU;EAAE,MAAM;EAAO,OAAO;CAAM;CACtC,YAAY;EAAE,MAAM;EAAU,OAAO;CAAQ;CAC7C,aAAa;EAAE,MAAM;EAAU,OAAO;CAAM;CAC5C,SAAS;EAAE,MAAM;EAAQ,OAAO;CAAQ;CACxC,YAAY;EAAE,MAAM;EAAQ,OAAO;CAAM;CACzC,UAAU;EAAE,MAAM;EAAS,OAAO;CAAQ;CAC1C,aAAa;EAAE,MAAM;EAAS,OAAO;CAAM;AAC7C;AAmBA,MAAM,WAAW,EACf,UACA,SACA,WACA,YAAY,OACZ,SAAS,GACT,OACA,YACA,GAAG,YACQ;CACX,MAAM,UAAU,SAAS,KAAK,QAAQ;CACtC,MAAM,EAAE,MAAM,UAAU,aAAa;CAErC,OACE,qBAAC,MAAD;EAAM,GAAI;EAAV,UAAA,CACE,oBAAC,gBAAD;GAAgB,QAAQ;GAAgB;GAAmB;EAAa,CAAA,GACxE,oBAAC,gBAAD;GACQ;GACC;GACP,YAAY;GACD;GAEV,UAAA;EACa,CAAA,CACZ;;AAEV"}
|
|
@@ -3,6 +3,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
3
3
|
//#region src/components/atoms/typography/paragraph.tsx
|
|
4
4
|
const Paragraph = ({ children, className, ...props }) => {
|
|
5
5
|
return /* @__PURE__ */ jsx("p", {
|
|
6
|
+
"data-slot": "typography-paragraph",
|
|
6
7
|
...props,
|
|
7
8
|
className: cn("m-0", className),
|
|
8
9
|
children
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paragraph.mjs","names":[],"sources":["../../../../src/components/atoms/typography/paragraph.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nexport interface Props extends React.ComponentPropsWithoutRef<'p'> {}\n\nconst Paragraph = ({ children, className, ...props }: Props) => {\n return (\n <p\n {...props}\n className={cn(\n 'm-0',\n className,\n //\n )}\n >\n {children}\n </p>\n );\n};\n\nexport default Paragraph;\n"],"mappings":";;;AAIA,MAAM,aAAa,EAAE,UAAU,WAAW,GAAG,YAAmB;CAC9D,OACE,oBAAC,KAAD;EACE,GAAI;EACJ,WAAW,GACT,OACA,SAEF;EAEC;CACA,CAAA;AAEP"}
|
|
1
|
+
{"version":3,"file":"paragraph.mjs","names":[],"sources":["../../../../src/components/atoms/typography/paragraph.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nexport interface Props extends React.ComponentPropsWithoutRef<'p'> {}\n\nconst Paragraph = ({ children, className, ...props }: Props) => {\n return (\n <p\n data-slot=\"typography-paragraph\"\n {...props}\n className={cn(\n 'm-0',\n className,\n //\n )}\n >\n {children}\n </p>\n );\n};\n\nexport default Paragraph;\n"],"mappings":";;;AAIA,MAAM,aAAa,EAAE,UAAU,WAAW,GAAG,YAAmB;CAC9D,OACE,oBAAC,KAAD;EACE,aAAU;EACV,GAAI;EACJ,WAAW,GACT,OACA,SAEF;EAEC;CACA,CAAA;AAEP"}
|
|
@@ -12,6 +12,7 @@ const styles = {
|
|
|
12
12
|
const Title = ({ children, level = 1, className, ...props }) => {
|
|
13
13
|
const Element = level < 1 || level > 6 ? "h1" : `h${level}`;
|
|
14
14
|
return /* @__PURE__ */ jsx(Element, {
|
|
15
|
+
"data-slot": "typography-title",
|
|
15
16
|
className: cn("m-0 leading-snug font-bold", styles[Element], className),
|
|
16
17
|
...props,
|
|
17
18
|
children
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"title.mjs","names":[],"sources":["../../../../src/components/atoms/typography/title.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nexport interface Props extends React.ComponentPropsWithoutRef<\n 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n> {\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\ntype ElementType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n\n// Scale up at wider breakpoints instead of a single fixed size — the desktop\n// size stays the same as before, but narrow/mobile viewports now get a\n// smaller starting size instead of always rendering at the full desktop size.\nconst styles: Record<string, string> = {\n h1: 'text-4xl sm:text-5xl lg:text-6xl',\n h2: 'text-3xl sm:text-4xl lg:text-5xl',\n h3: 'text-2xl sm:text-3xl lg:text-4xl',\n h4: 'text-xl sm:text-2xl lg:text-3xl',\n h5: 'text-lg sm:text-xl lg:text-2xl',\n h6: 'text-base sm:text-lg lg:text-xl',\n};\n\nconst Title = ({ children, level = 1, className, ...props }: Props) => {\n const Element: ElementType = level < 1 || level > 6 ? 'h1' : `h${level}`;\n\n return (\n <Element\n className={cn('m-0 leading-snug font-bold', styles[Element], className)}\n {...props}\n >\n {children}\n </Element>\n );\n};\n\nexport default Title;\n"],"mappings":";;;AAaA,MAAM,SAAiC;CACrC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,SAAS,EAAE,UAAU,QAAQ,GAAG,WAAW,GAAG,YAAmB;CACrE,MAAM,UAAuB,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI;CAEjE,OACE,oBAAC,SAAD;EACE,WAAW,GAAG,8BAA8B,OAAO,UAAU,SAAS;EACtE,GAAI;EAEH;CACM,CAAA;AAEb"}
|
|
1
|
+
{"version":3,"file":"title.mjs","names":[],"sources":["../../../../src/components/atoms/typography/title.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nexport interface Props extends React.ComponentPropsWithoutRef<\n 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n> {\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\ntype ElementType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n\n// Scale up at wider breakpoints instead of a single fixed size — the desktop\n// size stays the same as before, but narrow/mobile viewports now get a\n// smaller starting size instead of always rendering at the full desktop size.\nconst styles: Record<string, string> = {\n h1: 'text-4xl sm:text-5xl lg:text-6xl',\n h2: 'text-3xl sm:text-4xl lg:text-5xl',\n h3: 'text-2xl sm:text-3xl lg:text-4xl',\n h4: 'text-xl sm:text-2xl lg:text-3xl',\n h5: 'text-lg sm:text-xl lg:text-2xl',\n h6: 'text-base sm:text-lg lg:text-xl',\n};\n\nconst Title = ({ children, level = 1, className, ...props }: Props) => {\n const Element: ElementType = level < 1 || level > 6 ? 'h1' : `h${level}`;\n\n return (\n <Element\n data-slot=\"typography-title\"\n className={cn('m-0 leading-snug font-bold', styles[Element], className)}\n {...props}\n >\n {children}\n </Element>\n );\n};\n\nexport default Title;\n"],"mappings":";;;AAaA,MAAM,SAAiC;CACrC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,SAAS,EAAE,UAAU,QAAQ,GAAG,WAAW,GAAG,YAAmB;CACrE,MAAM,UAAuB,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI;CAEjE,OACE,oBAAC,SAAD;EACE,aAAU;EACV,WAAW,GAAG,8BAA8B,OAAO,UAAU,SAAS;EACtE,GAAI;EAEH;CACM,CAAA;AAEb"}
|
|
@@ -3,8 +3,8 @@ import { cn } from "../../utils.mjs";
|
|
|
3
3
|
import "../../lib/z-layers.mjs";
|
|
4
4
|
import Menu from "./menu/menu.mjs";
|
|
5
5
|
import { useId, useRef } from "react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { useControllableState, useKeyPress } from "@jbpark/use-hooks";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { AnimatePresence, motion } from "motion/react";
|
|
9
9
|
//#region src/components/molecules/dropdown.tsx
|
|
10
10
|
const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange: _onOpenChange = () => {}, className, onMouseEnter, onMouseLeave, ...props }) => {
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { Props as Props$2 } from "./
|
|
1
|
+
import Breadcrumb, { Props } from "../../Breadcrumb.mjs";
|
|
2
|
+
import Card, { Props as Props$1 } from "../../Card.mjs";
|
|
3
|
+
import Menu, { Props as Props$2 } from "./menu/menu.mjs";
|
|
4
|
+
import Pagination, { Props as Props$3 } from "../../Pagination.mjs";
|
|
5
|
+
import { Props as Props$4 } from "./reveals/reveals.mjs";
|
|
4
6
|
import Reveals from "../../Reveals.mjs";
|
|
5
|
-
import Space, { Props as Props$
|
|
6
|
-
import Collapse, { Props as Props$
|
|
7
|
-
import Dropdown, { Props as Props$
|
|
8
|
-
import { Props as Props$
|
|
7
|
+
import Space, { Props as Props$5 } from "../../Space.mjs";
|
|
8
|
+
import Collapse, { Props as Props$6 } from "./collapse.mjs";
|
|
9
|
+
import Dropdown, { Props as Props$7 } from "./dropdown.mjs";
|
|
10
|
+
import { Props as Props$8 } from "./marquees/marquees.mjs";
|
|
9
11
|
import Marquees from "./marquees/index.mjs";
|
|
10
|
-
import { Props as Props$
|
|
12
|
+
import { Props as Props$9 } from "./splitter/splitter.mjs";
|
|
11
13
|
import Splitter from "./splitter/index.mjs";
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
+
import Tabs, { Props as Props$10 } from "./tabs.mjs";
|
|
15
|
+
import Upload, { Props as Props$11, UploadFile } from "./upload.mjs";
|
|
16
|
+
export { Breadcrumb, type Props as BreadcrumbProps, Card, type Props$1 as CardProps, Collapse, type Props$6 as CollapseProps, Dropdown, type Props$7 as DropdownProps, Marquees, type Props$8 as MarqueesProps, Menu, type Props$2 as MenuProps, Pagination, type Props$3 as PaginationProps, Reveals, type Props$4 as RevealsProps, Space, type Props$5 as SpaceProps, Splitter, type Props$9 as SplitterProps, Tabs, type Props$10 as TabsProps, Upload, type UploadFile, type Props$11 as UploadProps };
|
|
@@ -3,8 +3,8 @@ import { cn } from "../../../utils.mjs";
|
|
|
3
3
|
import usePauseOnHover from "./use-pause-on-hover.mjs";
|
|
4
4
|
import Item from "./item.mjs";
|
|
5
5
|
import { useEffect, useRef, useState } from "react";
|
|
6
|
-
import { jsx } from "react/jsx-runtime";
|
|
7
6
|
import { useMergedRef, useResponsiveSize, useThrottledValue } from "@jbpark/use-hooks";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/molecules/marquees/marquees.tsx
|
|
9
9
|
const Marquees = ({ className, items, speed, pauseOnHover = true, autoFill = true, gap, ...props }) => {
|
|
10
10
|
const [width, setWidth] = useState("100%");
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { cn } from "../../../utils.mjs";
|
|
3
3
|
import Item from "./item/item.mjs";
|
|
4
4
|
import { createElement, useMemo } from "react";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
5
|
import { useControllableState } from "@jbpark/use-hooks";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/components/molecules/menu/menu.tsx
|
|
8
8
|
const MENU_CLASSNAMES = [
|
|
9
9
|
"m-0",
|
|
@@ -45,6 +45,7 @@ const Menu = ({ items, mode = "vertical", defaultSelectedKeys = [], selectedKeys
|
|
|
45
45
|
_onSelect?.(params);
|
|
46
46
|
};
|
|
47
47
|
return /* @__PURE__ */ jsx("ul", {
|
|
48
|
+
"data-slot": "menu",
|
|
48
49
|
role: "menu",
|
|
49
50
|
className: cn(MENU_CLASSNAMES, mode === "horizontal" ? "flex" : "inline-block", className),
|
|
50
51
|
...props,
|
|
@@ -1 +1 @@
|
|
|
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 'm-0',\n 'list-none',\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;CACA;CACA;AAEF;AAIA,MAAa,qBACX,OACA,oBACiB;CACjB,MAAM,sBAAM,IAAI,IAAwB;CAExC,MAAM,OAAO,SAA4B;EACvC,MAAM,OAAO,gBAAgB,IAAI,KAAK,GAAG;EACzC,MAAM,mBAAmB,KAAK,UAAU,MAAK,UAAS,IAAI,KAAK,CAAC,KAAK;EACrE,MAAM,aAAa,QAAQ;EAC3B,IAAI,IAAI,KAAK,KAAK,UAAU;EAC5B,OAAO;CACT;CAEA,MAAM,QAAQ,GAAG;CACjB,OAAO;AACT;AAEA,MAAa,WACX,MACA,eACY;CACZ,IAAI,WAAW,IAAI,KAAK,GAAG,GACzB,OAAO;CAGT,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK,QAAQ,GACzC;OAAA,MAAM,SAAS,KAAK,UACvB,IAAI,QAAQ,OAAO,UAAU,GAC3B,OAAO;CAAA;CAKb,OAAO;AACT;AAEA,MAAM,QAAQ,EACZ,OACA,OAAO,YACP,sBAAsB,CAAC,GACvB,cAAc,eACd,WACA,YACA,QACA,QACA,cACA,SACA,UAAU,WACV,GAAG,YACY;CACf,MAAM,CAAC,cAAc,mBAAmB,qBAAkC;EACxE,OAAO;EACP,cAAc,uBAAuB,CAAC;CACxC,CAAC;CAED,MAAM,kBAAkB,cAChB,IAAI,IAAe,gBAAgB,CAAC,CAAC,GAC3C,CAAC,YAAY,CACf;CAEA,MAAM,eAAe,cACb,kBAAkB,SAAS,CAAC,GAAG,eAAe,GACpD,CAAC,OAAO,eAAe,CACzB;CAEA,MAAM,YAAY,WAKZ;EACJ,gBAAgB,CAAC,OAAO,GAAG,CAAC;EAC5B,YAAY,MAAM;CACpB;CAEA,OACE,oBAAC,MAAD;EACE,MAAK;EACL,WAAW,GACT,iBACA,SAAS,eAAe,SAAS,gBACjC,SACF;EACA,GAAI;EAEH,UAAA,OAAO,KAAK,MAAM,UACjB,8BAAC,MAAD;GACE,MAAA;GACA,GAAI;GACJ,KAAK,KAAK;GACV,SAAS,KAAK;GACd,SAAS,CAAC,KAAK,GAAG;GACX;GACO;GACR;GACM;GACJ;GACA;GACM;GACL;GACC;EACX,CAAA,CACF;CACC,CAAA;AAER"}
|
|
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 'm-0',\n 'list-none',\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 data-slot=\"menu\"\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;CACA;CACA;AAEF;AAIA,MAAa,qBACX,OACA,oBACiB;CACjB,MAAM,sBAAM,IAAI,IAAwB;CAExC,MAAM,OAAO,SAA4B;EACvC,MAAM,OAAO,gBAAgB,IAAI,KAAK,GAAG;EACzC,MAAM,mBAAmB,KAAK,UAAU,MAAK,UAAS,IAAI,KAAK,CAAC,KAAK;EACrE,MAAM,aAAa,QAAQ;EAC3B,IAAI,IAAI,KAAK,KAAK,UAAU;EAC5B,OAAO;CACT;CAEA,MAAM,QAAQ,GAAG;CACjB,OAAO;AACT;AAEA,MAAa,WACX,MACA,eACY;CACZ,IAAI,WAAW,IAAI,KAAK,GAAG,GACzB,OAAO;CAGT,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK,QAAQ,GACzC;OAAA,MAAM,SAAS,KAAK,UACvB,IAAI,QAAQ,OAAO,UAAU,GAC3B,OAAO;CAAA;CAKb,OAAO;AACT;AAEA,MAAM,QAAQ,EACZ,OACA,OAAO,YACP,sBAAsB,CAAC,GACvB,cAAc,eACd,WACA,YACA,QACA,QACA,cACA,SACA,UAAU,WACV,GAAG,YACY;CACf,MAAM,CAAC,cAAc,mBAAmB,qBAAkC;EACxE,OAAO;EACP,cAAc,uBAAuB,CAAC;CACxC,CAAC;CAED,MAAM,kBAAkB,cAChB,IAAI,IAAe,gBAAgB,CAAC,CAAC,GAC3C,CAAC,YAAY,CACf;CAEA,MAAM,eAAe,cACb,kBAAkB,SAAS,CAAC,GAAG,eAAe,GACpD,CAAC,OAAO,eAAe,CACzB;CAEA,MAAM,YAAY,WAKZ;EACJ,gBAAgB,CAAC,OAAO,GAAG,CAAC;EAC5B,YAAY,MAAM;CACpB;CAEA,OACE,oBAAC,MAAD;EACE,aAAU;EACV,MAAK;EACL,WAAW,GACT,iBACA,SAAS,eAAe,SAAS,gBACjC,SACF;EACA,GAAI;EAEH,UAAA,OAAO,KAAK,MAAM,UACjB,8BAAC,MAAD;GACE,MAAA;GACA,GAAI;GACJ,KAAK,KAAK;GACV,SAAS,KAAK;GACd,SAAS,CAAC,KAAK,GAAG;GACX;GACO;GACR;GACM;GACJ;GACA;GACM;GACL;GACC;EACX,CAAA,CACF;CACC,CAAA;AAER"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Tabs as Tabs$1 } from "../../core/tabs.mjs";
|
|
2
|
+
import "../../core/index.mjs";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/components/molecules/tabs.d.ts
|
|
5
|
+
declare const Core: typeof Tabs$1;
|
|
6
|
+
interface Item {
|
|
7
|
+
key: string;
|
|
8
|
+
label: ReactNode;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Decorative icon rendered before the label with consistent spacing. */
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
interface Props extends Omit<React.ComponentProps<typeof Core>, 'children'> {
|
|
15
|
+
items: Item[];
|
|
16
|
+
listLabel?: string;
|
|
17
|
+
/** Preserve inactive panel DOM and local state. */
|
|
18
|
+
keepMounted?: boolean;
|
|
19
|
+
/** Select a tab when arrow-key focus moves to it. */
|
|
20
|
+
activateOnFocus?: boolean;
|
|
21
|
+
/** Scroll the tab list when its items exceed the available space. */
|
|
22
|
+
scrollable?: boolean;
|
|
23
|
+
/** Give tabs equal width in horizontal mode; ignored when scrollable. */
|
|
24
|
+
fitted?: boolean;
|
|
25
|
+
/** Content shown after the tab list, outside the tablist role. */
|
|
26
|
+
extra?: ReactNode;
|
|
27
|
+
classNames?: {
|
|
28
|
+
list?: string;
|
|
29
|
+
tab?: string;
|
|
30
|
+
panel?: string;
|
|
31
|
+
extra?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
declare const Tabs: ({ items, listLabel, keepMounted, activateOnFocus, scrollable, fitted, extra, classNames, defaultValue, orientation, ...props }: Props) => import("react").JSX.Element;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Item, Props, Tabs as default };
|
|
37
|
+
//# sourceMappingURL=tabs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.d.mts","names":[],"sources":["../../../src/components/molecules/tabs.tsx"],"mappings":";;;;cAQc,aAAI;UAED;EACf;EACA,OAAO;EACP,UAAU;EACV;;EAEA,OAAO;;UAGQ,cAAc,KAC7B,MAAM,sBAAsB;EAG5B,OAAO;EACP;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,QAAQ;EACR;IACE;IACA;IACA;IACA;;;cAIE,SAAQ,OAAA,WAAA,aAAA,iBAAA,YAAA,QAAA,OAAA,YAAA,cAAA,gBAAA,SAYX,0BAAK,IAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../utils.mjs";
|
|
3
|
+
import { tabs_exports } from "../../core/tabs.mjs";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/molecules/tabs.tsx
|
|
6
|
+
const { Tabs: Core, TabsList, TabsTab, TabsPanel } = tabs_exports;
|
|
7
|
+
const Tabs = ({ items, listLabel = "Tabs", keepMounted = false, activateOnFocus = false, scrollable = false, fitted = false, extra, classNames, defaultValue, orientation = "horizontal", ...props }) => {
|
|
8
|
+
const initialValue = defaultValue === void 0 ? items.find((item) => !item.disabled)?.key : defaultValue;
|
|
9
|
+
return /* @__PURE__ */ jsxs(Core, {
|
|
10
|
+
defaultValue: props.value === void 0 ? initialValue : void 0,
|
|
11
|
+
orientation,
|
|
12
|
+
...props,
|
|
13
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
14
|
+
"data-slot": "tabs-bar",
|
|
15
|
+
className: cn("flex min-w-0 items-stretch", orientation === "vertical" && "min-h-0 shrink-0 flex-col"),
|
|
16
|
+
children: [/* @__PURE__ */ jsx(TabsList, {
|
|
17
|
+
"aria-label": listLabel,
|
|
18
|
+
activateOnFocus,
|
|
19
|
+
className: cn("min-w-0 flex-1", scrollable && (orientation === "vertical" ? "min-h-0 overflow-y-auto" : `[scrollbar-width:none] overflow-x-auto overflow-y-hidden
|
|
20
|
+
[&::-webkit-scrollbar]:hidden`), classNames?.list),
|
|
21
|
+
children: items.map((item) => /* @__PURE__ */ jsxs(TabsTab, {
|
|
22
|
+
value: item.key,
|
|
23
|
+
disabled: item.disabled,
|
|
24
|
+
className: cn(fitted && !scrollable && orientation === "horizontal" && "flex-1", scrollable && "shrink-0", classNames?.tab),
|
|
25
|
+
children: [item.icon != null && /* @__PURE__ */ jsx("span", {
|
|
26
|
+
"data-slot": "tabs-icon",
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
className: "inline-flex shrink-0 items-center",
|
|
29
|
+
children: item.icon
|
|
30
|
+
}), item.label]
|
|
31
|
+
}, item.key))
|
|
32
|
+
}), extra != null && /* @__PURE__ */ jsx("div", {
|
|
33
|
+
"data-slot": "tabs-extra",
|
|
34
|
+
className: cn(`border-border flex shrink-0 items-center border-b px-3
|
|
35
|
+
data-[orientation=vertical]:border-r
|
|
36
|
+
data-[orientation=vertical]:border-b-0`, classNames?.extra),
|
|
37
|
+
"data-orientation": orientation,
|
|
38
|
+
children: extra
|
|
39
|
+
})]
|
|
40
|
+
}), items.map((item) => /* @__PURE__ */ jsx(TabsPanel, {
|
|
41
|
+
value: item.key,
|
|
42
|
+
keepMounted,
|
|
43
|
+
className: classNames?.panel,
|
|
44
|
+
children: item.children
|
|
45
|
+
}, item.key))]
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { Tabs as default };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=tabs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.mjs","names":["tabs"],"sources":["../../../src/components/molecules/tabs.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { tabs } from '../../core';\n\nconst { Tabs: Core, TabsList, TabsTab, TabsPanel } = tabs;\n\nexport interface Item {\n key: string;\n label: ReactNode;\n children: ReactNode;\n disabled?: boolean;\n /** Decorative icon rendered before the label with consistent spacing. */\n icon?: ReactNode;\n}\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'children'\n> {\n items: Item[];\n listLabel?: string;\n /** Preserve inactive panel DOM and local state. */\n keepMounted?: boolean;\n /** Select a tab when arrow-key focus moves to it. */\n activateOnFocus?: boolean;\n /** Scroll the tab list when its items exceed the available space. */\n scrollable?: boolean;\n /** Give tabs equal width in horizontal mode; ignored when scrollable. */\n fitted?: boolean;\n /** Content shown after the tab list, outside the tablist role. */\n extra?: ReactNode;\n classNames?: {\n list?: string;\n tab?: string;\n panel?: string;\n extra?: string;\n };\n}\n\nconst Tabs = ({\n items,\n listLabel = 'Tabs',\n keepMounted = false,\n activateOnFocus = false,\n scrollable = false,\n fitted = false,\n extra,\n classNames,\n defaultValue,\n orientation = 'horizontal',\n ...props\n}: Props) => {\n const initialValue =\n defaultValue === undefined\n ? items.find(item => !item.disabled)?.key\n : defaultValue;\n\n return (\n <Core\n defaultValue={props.value === undefined ? initialValue : undefined}\n orientation={orientation}\n {...props}\n >\n <div\n data-slot=\"tabs-bar\"\n className={cn(\n 'flex min-w-0 items-stretch',\n orientation === 'vertical' && 'min-h-0 shrink-0 flex-col',\n //\n )}\n >\n <TabsList\n aria-label={listLabel}\n activateOnFocus={activateOnFocus}\n className={cn(\n 'min-w-0 flex-1',\n scrollable &&\n (orientation === 'vertical'\n ? 'min-h-0 overflow-y-auto'\n : `[scrollbar-width:none] overflow-x-auto overflow-y-hidden\n [&::-webkit-scrollbar]:hidden`),\n classNames?.list,\n //\n )}\n >\n {items.map(item => (\n <TabsTab\n key={item.key}\n value={item.key}\n disabled={item.disabled}\n className={cn(\n fitted &&\n !scrollable &&\n orientation === 'horizontal' &&\n 'flex-1',\n scrollable && 'shrink-0',\n classNames?.tab,\n //\n )}\n >\n {item.icon != null && (\n <span\n data-slot=\"tabs-icon\"\n aria-hidden=\"true\"\n className=\"inline-flex shrink-0 items-center\"\n >\n {item.icon}\n </span>\n )}\n {item.label}\n </TabsTab>\n ))}\n </TabsList>\n {extra != null && (\n <div\n data-slot=\"tabs-extra\"\n className={cn(\n `border-border flex shrink-0 items-center border-b px-3\n data-[orientation=vertical]:border-r\n data-[orientation=vertical]:border-b-0`,\n classNames?.extra,\n //\n )}\n data-orientation={orientation}\n >\n {extra}\n </div>\n )}\n </div>\n {items.map(item => (\n <TabsPanel\n key={item.key}\n value={item.key}\n keepMounted={keepMounted}\n className={classNames?.panel}\n >\n {item.children}\n </TabsPanel>\n ))}\n </Core>\n );\n};\n\nexport default Tabs;\n"],"mappings":";;;;;AAQA,MAAM,EAAE,MAAM,MAAM,UAAU,SAAS,cAAcA;AAmCrD,MAAM,QAAQ,EACZ,OACA,YAAY,QACZ,cAAc,OACd,kBAAkB,OAClB,aAAa,OACb,SAAS,OACT,OACA,YACA,cACA,cAAc,cACd,GAAG,YACQ;CACX,MAAM,eACJ,iBAAiB,KAAA,IACb,MAAM,MAAK,SAAQ,CAAC,KAAK,QAAQ,CAAC,EAAE,MACpC;CAEN,OACE,qBAAC,MAAD;EACE,cAAc,MAAM,UAAU,KAAA,IAAY,eAAe,KAAA;EAC5C;EACb,GAAI;EAHN,UAAA,CAKE,qBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,8BACA,gBAAgB,cAAc,2BAEhC;GANF,UAAA,CAQE,oBAAC,UAAD;IACE,cAAY;IACK;IACjB,WAAW,GACT,kBACA,eACG,gBAAgB,aACb,4BACA;mDAEN,YAAY,IAEd;IAEC,UAAA,MAAM,KAAI,SACT,qBAAC,SAAD;KAEE,OAAO,KAAK;KACZ,UAAU,KAAK;KACf,WAAW,GACT,UACE,CAAC,cACD,gBAAgB,gBAChB,UACF,cAAc,YACd,YAAY,GAEd;KAZF,UAAA,CAcG,KAAK,QAAQ,QACZ,oBAAC,QAAD;MACE,aAAU;MACV,eAAY;MACZ,WAAU;MAET,UAAA,KAAK;KACF,CAAA,GAEP,KAAK,KACC;IAvBF,GAAA,KAAK,GAuBH,CACV;GACO,CAAA,GACT,SAAS,QACR,oBAAC,OAAD;IACE,aAAU;IACV,WAAW,GACT;;uDAGA,YAAY,KAEd;IACA,oBAAkB;IAEjB,UAAA;GACE,CAAA,CAEJ;EACJ,CAAA,GAAA,MAAM,KAAI,SACT,oBAAC,WAAD;GAEE,OAAO,KAAK;GACC;GACb,WAAW,YAAY;GAEtB,UAAA,KAAK;EACG,GANJ,KAAK,GAMD,CACZ,CACG;;AAEV"}
|
|
@@ -3,8 +3,8 @@ import { cn } from "../../utils.mjs";
|
|
|
3
3
|
import Button from "../../Button.mjs";
|
|
4
4
|
import { useId } from "react";
|
|
5
5
|
import { Upload, X } from "lucide-react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { useControllableState, useFileDrop, useFileToDataUrl } from "@jbpark/use-hooks";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/molecules/upload.tsx
|
|
9
9
|
let uidCounter = 0;
|
|
10
10
|
const nextUid = () => uidCounter += 1;
|
|
@@ -53,6 +53,7 @@ const Upload$1 = ({ defaultValue = [], value: _value, multiple = true, accept =
|
|
|
53
53
|
onDrop: addFiles
|
|
54
54
|
});
|
|
55
55
|
return /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
"data-slot": "upload",
|
|
56
57
|
className: cn("flex flex-col gap-3", className),
|
|
57
58
|
children: [/* @__PURE__ */ jsxs("label", {
|
|
58
59
|
ref: dropRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.mjs","names":["Upload","UploadIcon"],"sources":["../../../src/components/molecules/upload.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport {\n useControllableState,\n useFileDrop,\n useFileToDataUrl,\n} from '@jbpark/use-hooks';\nimport { Upload as UploadIcon, X } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\n// Monotonic per-session counter used as a uniqueness tiebreaker for file\n// uids. Guarantees a unique suffix even for the same file (identical\n// name/lastModified/size) added twice, which name+lastModified+size alone\n// can't. These uids are internal React keys, not cryptographic, so a plain\n// counter is enough — and it avoids a runtime `uuid` dependency.\nlet uidCounter = 0;\nconst nextUid = () => (uidCounter += 1);\n\nexport interface UploadFile {\n uid: string;\n name: string;\n url: string;\n}\n\nexport interface Props {\n defaultValue?: UploadFile[];\n value?: UploadFile[];\n multiple?: boolean;\n accept?: string;\n maxCount?: number;\n disabled?: boolean;\n className?: string;\n classNames?: {\n dropzone?: string;\n list?: string;\n item?: string;\n };\n onChange?: (files: UploadFile[]) => void;\n /**\n * Called once per file that didn't make it in — either bumped by\n * `maxCount` or failed to read.\n */\n onReject?: (info: { file: File; reason: 'max-count' | 'read-error' }) => void;\n}\n\nconst isImage = (file: UploadFile) =>\n /^data:image\\//.test(file.url) ||\n /\\.(png|jpe?g|gif|webp|svg)$/i.test(file.name);\n\nconst Upload = ({\n defaultValue = [],\n value: _value,\n multiple = true,\n accept = 'image/*',\n maxCount,\n disabled,\n className,\n classNames,\n onChange: _onChange = () => {},\n onReject,\n}: Props) => {\n const inputId = useId();\n const readAsDataUrl = useFileToDataUrl();\n const [files, setFiles] = useControllableState<UploadFile[]>({\n value: _value,\n defaultValue,\n onChange: _onChange,\n });\n\n const addFiles = async (incoming: File[]) => {\n const remaining =\n typeof maxCount === 'number'\n ? Math.max(0, maxCount - files.length)\n : incoming.length;\n\n const accepted = incoming.slice(0, remaining);\n const rejected = incoming.slice(remaining);\n\n rejected.forEach(file => onReject?.({ file, reason: 'max-count' }));\n\n if (accepted.length === 0) {\n return;\n }\n\n const uploaded = (\n await Promise.all(\n accepted.map(async file => {\n try {\n return {\n // `nextUid()` guarantees uniqueness even for the same file\n // added twice (identical name/lastModified/size), which\n // name+lastModified+size alone can't — a collision there\n // corrupted React's item keys and made removeFile's\n // uid-based filter delete both copies at once.\n uid: `${file.name}-${file.lastModified}-${file.size}-${nextUid()}`,\n name: file.name,\n url: await readAsDataUrl(file),\n };\n } catch {\n onReject?.({ file, reason: 'read-error' });\n return null;\n }\n }),\n )\n ).filter((file): file is UploadFile => file !== null);\n\n if (uploaded.length === 0) {\n return;\n }\n\n setFiles([...files, ...uploaded]);\n };\n\n const removeFile = (uid: string) => {\n setFiles(files.filter(file => file.uid !== uid));\n };\n\n const { dropRef, isDragging } = useFileDrop<HTMLLabelElement>({\n accept,\n multiple,\n disabled,\n onDrop: addFiles,\n });\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3',\n className,\n //\n )}\n >\n <label\n ref={dropRef}\n htmlFor={inputId}\n className={cn(\n 'flex cursor-pointer flex-col items-center justify-center gap-2',\n 'rounded-md border border-dashed p-6 text-center',\n 'text-muted-foreground text-sm',\n 'transition-colors',\n isDragging && 'border-primary bg-accent',\n disabled && 'pointer-events-none cursor-not-allowed opacity-50',\n classNames?.dropzone,\n //\n )}\n >\n <UploadIcon className=\"size-6\" />\n <span>Click or drag file{multiple ? 's' : ''} to upload</span>\n <input\n id={inputId}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className=\"hidden\"\n onChange={e => {\n if (e.target.files?.length) {\n addFiles(Array.from(e.target.files));\n }\n e.target.value = '';\n }}\n />\n </label>\n\n {files.length > 0 && (\n <ul\n className={cn(\n 'm-0 flex list-none flex-col gap-2 p-0',\n classNames?.list,\n //\n )}\n >\n {files.map(file => (\n <li\n key={file.uid}\n className={cn(\n // `m-0` completes the list reset the `ul` above starts — see\n // Radio.Group for the host rule this guards against.\n 'm-0 flex items-center gap-2 rounded-md border p-2',\n classNames?.item,\n //\n )}\n >\n {isImage(file) && (\n <img\n src={file.url}\n alt=\"\"\n className=\"size-10 shrink-0 rounded object-cover\"\n />\n )}\n <span className=\"flex-1 truncate text-sm\">{file.name}</span>\n <Button\n variant=\"text\"\n shape=\"circle\"\n size=\"small\"\n icon={<X className=\"size-4\" />}\n onClick={() => removeFile(file.uid)}\n className=\"text-muted-foreground hover:text-foreground shrink-0\"\n aria-label={`Remove ${file.name}`}\n />\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nexport default Upload;\n"],"mappings":";;;;;;;;AAoBA,IAAI,aAAa;AACjB,MAAM,gBAAiB,cAAc;AA6BrC,MAAM,WAAW,SACf,gBAAgB,KAAK,KAAK,GAAG,KAC7B,+BAA+B,KAAK,KAAK,IAAI;AAE/C,MAAMA,YAAU,EACd,eAAe,CAAC,GAChB,OAAO,QACP,WAAW,MACX,SAAS,WACT,UACA,UACA,WACA,YACA,UAAU,kBAAkB,CAAC,GAC7B,eACW;CACX,MAAM,UAAU,MAAM;CACtB,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,CAAC,OAAO,YAAY,qBAAmC;EAC3D,OAAO;EACP;EACA,UAAU;CACZ,CAAC;CAED,MAAM,WAAW,OAAO,aAAqB;EAC3C,MAAM,YACJ,OAAO,aAAa,WAChB,KAAK,IAAI,GAAG,WAAW,MAAM,MAAM,IACnC,SAAS;EAEf,MAAM,WAAW,SAAS,MAAM,GAAG,SAAS;EAG5C,SAF0B,MAAM,SAEzB,CAAC,CAAC,SAAQ,SAAQ,WAAW;GAAE;GAAM,QAAQ;EAAY,CAAC,CAAC;EAElE,IAAI,SAAS,WAAW,GACtB;EAGF,MAAM,YACJ,MAAM,QAAQ,IACZ,SAAS,IAAI,OAAM,SAAQ;GACzB,IAAI;IACF,OAAO;KAML,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,aAAa,GAAG,KAAK,KAAK,GAAG,QAAQ;KAC/D,MAAM,KAAK;KACX,KAAK,MAAM,cAAc,IAAI;IAC/B;GACF,QAAQ;IACN,WAAW;KAAE;KAAM,QAAQ;IAAa,CAAC;IACzC,OAAO;GACT;EACF,CAAC,CACH,EAAA,CACA,QAAQ,SAA6B,SAAS,IAAI;EAEpD,IAAI,SAAS,WAAW,GACtB;EAGF,SAAS,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC;CAClC;CAEA,MAAM,cAAc,QAAgB;EAClC,SAAS,MAAM,QAAO,SAAQ,KAAK,QAAQ,GAAG,CAAC;CACjD;CAEA,MAAM,EAAE,SAAS,eAAe,YAA8B;EAC5D;EACA;EACA;EACA,QAAQ;CACV,CAAC;CAED,OACE,qBAAC,OAAD;EACE,WAAW,GACT,uBACA,SAEF;
|
|
1
|
+
{"version":3,"file":"upload.mjs","names":["Upload","UploadIcon"],"sources":["../../../src/components/molecules/upload.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport {\n useControllableState,\n useFileDrop,\n useFileToDataUrl,\n} from '@jbpark/use-hooks';\nimport { Upload as UploadIcon, X } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\n// Monotonic per-session counter used as a uniqueness tiebreaker for file\n// uids. Guarantees a unique suffix even for the same file (identical\n// name/lastModified/size) added twice, which name+lastModified+size alone\n// can't. These uids are internal React keys, not cryptographic, so a plain\n// counter is enough — and it avoids a runtime `uuid` dependency.\nlet uidCounter = 0;\nconst nextUid = () => (uidCounter += 1);\n\nexport interface UploadFile {\n uid: string;\n name: string;\n url: string;\n}\n\nexport interface Props {\n defaultValue?: UploadFile[];\n value?: UploadFile[];\n multiple?: boolean;\n accept?: string;\n maxCount?: number;\n disabled?: boolean;\n className?: string;\n classNames?: {\n dropzone?: string;\n list?: string;\n item?: string;\n };\n onChange?: (files: UploadFile[]) => void;\n /**\n * Called once per file that didn't make it in — either bumped by\n * `maxCount` or failed to read.\n */\n onReject?: (info: { file: File; reason: 'max-count' | 'read-error' }) => void;\n}\n\nconst isImage = (file: UploadFile) =>\n /^data:image\\//.test(file.url) ||\n /\\.(png|jpe?g|gif|webp|svg)$/i.test(file.name);\n\nconst Upload = ({\n defaultValue = [],\n value: _value,\n multiple = true,\n accept = 'image/*',\n maxCount,\n disabled,\n className,\n classNames,\n onChange: _onChange = () => {},\n onReject,\n}: Props) => {\n const inputId = useId();\n const readAsDataUrl = useFileToDataUrl();\n const [files, setFiles] = useControllableState<UploadFile[]>({\n value: _value,\n defaultValue,\n onChange: _onChange,\n });\n\n const addFiles = async (incoming: File[]) => {\n const remaining =\n typeof maxCount === 'number'\n ? Math.max(0, maxCount - files.length)\n : incoming.length;\n\n const accepted = incoming.slice(0, remaining);\n const rejected = incoming.slice(remaining);\n\n rejected.forEach(file => onReject?.({ file, reason: 'max-count' }));\n\n if (accepted.length === 0) {\n return;\n }\n\n const uploaded = (\n await Promise.all(\n accepted.map(async file => {\n try {\n return {\n // `nextUid()` guarantees uniqueness even for the same file\n // added twice (identical name/lastModified/size), which\n // name+lastModified+size alone can't — a collision there\n // corrupted React's item keys and made removeFile's\n // uid-based filter delete both copies at once.\n uid: `${file.name}-${file.lastModified}-${file.size}-${nextUid()}`,\n name: file.name,\n url: await readAsDataUrl(file),\n };\n } catch {\n onReject?.({ file, reason: 'read-error' });\n return null;\n }\n }),\n )\n ).filter((file): file is UploadFile => file !== null);\n\n if (uploaded.length === 0) {\n return;\n }\n\n setFiles([...files, ...uploaded]);\n };\n\n const removeFile = (uid: string) => {\n setFiles(files.filter(file => file.uid !== uid));\n };\n\n const { dropRef, isDragging } = useFileDrop<HTMLLabelElement>({\n accept,\n multiple,\n disabled,\n onDrop: addFiles,\n });\n\n return (\n <div\n data-slot=\"upload\"\n className={cn(\n 'flex flex-col gap-3',\n className,\n //\n )}\n >\n <label\n ref={dropRef}\n htmlFor={inputId}\n className={cn(\n 'flex cursor-pointer flex-col items-center justify-center gap-2',\n 'rounded-md border border-dashed p-6 text-center',\n 'text-muted-foreground text-sm',\n 'transition-colors',\n isDragging && 'border-primary bg-accent',\n disabled && 'pointer-events-none cursor-not-allowed opacity-50',\n classNames?.dropzone,\n //\n )}\n >\n <UploadIcon className=\"size-6\" />\n <span>Click or drag file{multiple ? 's' : ''} to upload</span>\n <input\n id={inputId}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className=\"hidden\"\n onChange={e => {\n if (e.target.files?.length) {\n addFiles(Array.from(e.target.files));\n }\n e.target.value = '';\n }}\n />\n </label>\n\n {files.length > 0 && (\n <ul\n className={cn(\n 'm-0 flex list-none flex-col gap-2 p-0',\n classNames?.list,\n //\n )}\n >\n {files.map(file => (\n <li\n key={file.uid}\n className={cn(\n // `m-0` completes the list reset the `ul` above starts — see\n // Radio.Group for the host rule this guards against.\n 'm-0 flex items-center gap-2 rounded-md border p-2',\n classNames?.item,\n //\n )}\n >\n {isImage(file) && (\n <img\n src={file.url}\n alt=\"\"\n className=\"size-10 shrink-0 rounded object-cover\"\n />\n )}\n <span className=\"flex-1 truncate text-sm\">{file.name}</span>\n <Button\n variant=\"text\"\n shape=\"circle\"\n size=\"small\"\n icon={<X className=\"size-4\" />}\n onClick={() => removeFile(file.uid)}\n className=\"text-muted-foreground hover:text-foreground shrink-0\"\n aria-label={`Remove ${file.name}`}\n />\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nexport default Upload;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";UA2CiB;EACf;EACA,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,SAAS,MAAM;EACf;EACA,YAAY,MAAM;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,MAAM;EACd;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF,YAAY;EACZ;;
|
|
1
|
+
{"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";UA2CiB;EACf;EACA,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,SAAS,MAAM;EACf;EACA,YAAY,MAAM;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,MAAM;EACd;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF,YAAY;EACZ;;cA8CI,WAAU,MAAA,OAAA,OAAA,QAAA,UAAA,WAAA,WAAA,MAAA,cAAA,WAAA,SAAA,MAAA,WAAA,YAAA,OAAA,UAAA,WAAA,YAAA,SAoBb,0BAAK,IAAA"}
|
|
@@ -32,9 +32,14 @@ const ROUNDED_CLASSES = {
|
|
|
32
32
|
left: "rounded-r-[30px]!",
|
|
33
33
|
right: "rounded-l-[30px]!"
|
|
34
34
|
};
|
|
35
|
+
const SIDE_MIN_WIDTH = "20rem";
|
|
35
36
|
const getSizeStyles = (direction, size) => {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
if (direction === "top" || direction === "bottom") return { height: SIZES[size] || size };
|
|
38
|
+
const preset = SIZES[size];
|
|
39
|
+
return {
|
|
40
|
+
width: preset ? `max(${preset}, ${SIDE_MIN_WIDTH})` : size,
|
|
41
|
+
maxWidth: "100%"
|
|
42
|
+
};
|
|
38
43
|
};
|
|
39
44
|
const Drawer = ({ open, title, extra, footer, closable = true, closeIcon, direction = "bottom", size = "medium", maskClosable = true, handlebar = true, rounded = false, mask = true, className, classNames, style, children, container, onClose, ...props }) => {
|
|
40
45
|
const { locale } = useConfig();
|
|
@@ -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 { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { drawer } from '../../core';\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 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
|
|
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 { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { drawer } from '../../core';\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 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\n// A side drawer sized by a preset is sized by a percentage of the viewport,\n// which collapses on a phone: `small` is 30%, so it lands at ~112px on a 375px\n// screen — a sliver too narrow to read. Floor the preset widths so they stay\n// usable on small screens. A custom `size` is passed through untouched; an\n// explicit value is the caller's decision, not something to second-guess.\nconst SIDE_MIN_WIDTH = '20rem';\n\nconst getSizeStyles = (\n direction: 'top' | 'bottom' | 'left' | 'right',\n size: string,\n): React.CSSProperties => {\n if (direction === 'top' || direction === 'bottom') {\n return { height: SIZES[size] || size };\n }\n\n const preset = SIZES[size];\n\n return {\n width: preset ? `max(${preset}, ${SIDE_MIN_WIDTH})` : size,\n // Set inline so it beats `core/drawer`'s `sm:max-w-sm`, which would\n // otherwise hold every side drawer at 24rem from the `sm` breakpoint up\n // and leave `size` with no effect on anything wider than a phone. It also\n // keeps the floor above from overflowing a container narrower than it.\n maxWidth: '100%',\n };\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 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 // antd's mask ⇒ Base UI's modal (focus trap + scroll lock); maskClosable\n // gates outside-press dismissal at the root, replacing vaul's\n // Content-level onPointerDownOutside handler.\n modal={mask}\n disablePointerDismissal={!maskClosable}\n onOpenChange={open => {\n if (!open) {\n onClose();\n }\n }}\n {...props}\n >\n <DrawerContent\n direction={direction}\n container={container}\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 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 variant=\"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 {extra != null && (\n <div className={cn('shrink-0', classNames?.extra)}>{extra}</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 {footer != null && (\n <DrawerFooter className={cn(classNames?.footer)}>\n {footer}\n </DrawerFooter>\n )}\n </DrawerContent>\n </DrawerCore>\n );\n};\n\nexport default Drawer;\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Props as Props$1 } from "./
|
|
1
|
+
import Table, { Column, PaginationOptions, Props } from "../../Table.mjs";
|
|
2
|
+
import Drawer, { Props as Props$1 } from "./drawer.mjs";
|
|
3
|
+
import { Props as Props$2 } from "./list/list.mjs";
|
|
3
4
|
import List from "./list/index.mjs";
|
|
4
|
-
import Modal, { Props as Props$
|
|
5
|
-
import { Props as Props$
|
|
5
|
+
import Modal, { Props as Props$3 } from "./modal.mjs";
|
|
6
|
+
import { Props as Props$4 } from "./swiper/swiper.mjs";
|
|
6
7
|
import Swiper from "./swiper/index.mjs";
|
|
7
8
|
import Toast, { ToastOptions as StaticProps } from "./toast.mjs";
|
|
8
|
-
export { Drawer, type Props as DrawerProps, List, type Props$
|
|
9
|
+
export { Drawer, type Props$1 as DrawerProps, List, type Props$2 as ListProps, Modal, type Props$3 as ModalProps, Swiper, type Props$4 as SwiperProps, Table, type Column as TableColumn, type PaginationOptions as TablePaginationOptions, type Props as TableProps, Toast, type StaticProps as ToastOptions };
|
|
@@ -3,8 +3,8 @@ import { cn, renderConditional } from "../../../utils.mjs";
|
|
|
3
3
|
import Title from "../../atoms/typography/title.mjs";
|
|
4
4
|
import Skeleton from "../../atoms/skeleton/index.mjs";
|
|
5
5
|
import { useEffect, useRef } from "react";
|
|
6
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { useIntersectionObserver } from "@jbpark/use-hooks";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/organisms/list/list.tsx
|
|
9
9
|
const List = ({ loading, loaderProps, loader, header, title, titleLevel = 2, empty, scroll, data, className, classNames, renderItem = () => null, itemKey, ...props }) => {
|
|
10
10
|
const [loaderRef, { isIntersecting }] = useIntersectionObserver({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;UAiCiB;EACf;EACA;EACA;IAGM,YAAY,MAAM;IAClB;;EAEN,YAAY,MAAM;EAClB,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,SAAS,MAAM;EACf;EACA;IACE;IACA;IACA;IACA;;EAEF,QAAQ,MAAM;EACd;EACA;EACA,YAAY;EACZ,WAAW,MAAM;EACjB;EACA;;KAGG;UAEK,oBAAoB;EAC5B,SAAS;;;;;;EAMT;EACA;EACA,OAAO,MAAM;EACb,YAAY;;cAGR;KAkBH,MAAA,cAAA,UAAA,WAAA,WAAA,YAAA,OAAA,OAAA,SAAA,QAAA,WAAA,UAAA,QAAA,YAAA,MAAA,aAAA,SAAA,QAAK,MAAA,IAAA;;;
|
|
1
|
+
{"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;UAiCiB;EACf;EACA;EACA;IAGM,YAAY,MAAM;IAClB;;EAEN,YAAY,MAAM;EAClB,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,SAAS,MAAM;EACf;EACA;IACE;IACA;IACA;IACA;;EAEF,QAAQ,MAAM;EACd;EACA;EACA,YAAY;EACZ,WAAW,MAAM;EACjB;EACA;;KAGG;UAEK,oBAAoB;EAC5B,SAAS;;;;;;EAMT;EACA;EACA,OAAO,MAAM;EACb,YAAY;;cAGR;KAkBH,MAAA,cAAA,UAAA,WAAA,WAAA,YAAA,OAAA,OAAA,SAAA,QAAA,WAAA,UAAA,QAAA,YAAA,MAAA,aAAA,SAAA,QAAK,MAAA,IAAA;;;EAuOa,KAAA,OAAA;EAEG,QAAA,OAAA;EAEF,MAAA,OAAA;EAEE,QAAA,OAAA;EAIA,QAAA,OAAA"}
|
|
@@ -44,6 +44,7 @@ const Modal = ({ open = false, maskClosable, closable = false, closeIcon, classN
|
|
|
44
44
|
footer !== null && /* @__PURE__ */ jsx(DialogFooter, {
|
|
45
45
|
className: cn("flex-row justify-end gap-x-2", classNames?.footer),
|
|
46
46
|
children: footer || /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
|
|
47
|
+
type: "primary",
|
|
47
48
|
onClick: onOk,
|
|
48
49
|
children: okText ?? locale.ok ?? DEFAULT_LOCALE.ok
|
|
49
50
|
}), /* @__PURE__ */ jsx(Button, {
|
|
@@ -79,16 +80,18 @@ const StaticModal = ({ id, status, mode, title, content, okText, cancelText, con
|
|
|
79
80
|
const footer = isConfirm ? /* @__PURE__ */ jsxs("div", {
|
|
80
81
|
className: "grid w-full grid-cols-5 gap-x-2",
|
|
81
82
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
83
|
+
type: "primary",
|
|
84
|
+
className: "col-span-3",
|
|
85
|
+
onClick: () => closeModal(onOk),
|
|
86
|
+
children: resolvedOkText
|
|
87
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
82
88
|
variant: "outlined",
|
|
83
89
|
className: "col-span-2",
|
|
84
90
|
onClick: () => closeModal(onCancel),
|
|
85
91
|
children: resolvedCancelText
|
|
86
|
-
}), /* @__PURE__ */ jsx(Button, {
|
|
87
|
-
className: "col-span-3",
|
|
88
|
-
onClick: () => closeModal(onOk),
|
|
89
|
-
children: resolvedOkText
|
|
90
92
|
})]
|
|
91
93
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
94
|
+
type: "primary",
|
|
92
95
|
className: cn("grow"),
|
|
93
96
|
onClick: () => closeModal(onOk),
|
|
94
97
|
children: resolvedOkText
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.mjs","names":["dialog"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\n\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { dialog } from '../../core';\nimport Button from '../atoms/button';\nimport {\n type ImperativeStack,\n createImperativeStack,\n isBrowser,\n} from './imperative-stack';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\nexport interface Props {\n open?: boolean;\n maskClosable?: boolean;\n closable?:\n | boolean\n | {\n closeIcon?: React.ReactNode;\n disabled?: boolean;\n };\n closeIcon?: React.ReactNode;\n title?: React.ReactNode;\n content?: React.ReactNode;\n footer?: React.ReactNode;\n className?: string;\n classNames?: {\n mask?: string;\n header?: string;\n body?: string;\n footer?: string;\n };\n style?: React.CSSProperties;\n okText?: string;\n cancelText?: string;\n container?: HTMLElement;\n children?: React.ReactNode;\n onOk?: () => void;\n onCancel?: () => void;\n}\n\ntype ModalStatus = 'info' | 'success' | 'error' | 'warning';\n\ninterface StaticProps extends Props {\n status?: ModalStatus;\n /**\n * Interaction mode set by `Modal.confirm()` to request the two-button\n * footer. `confirm` is a mode, not a status, so it rides its own axis rather\n * than `status` — call `Modal.confirm()` rather than setting this directly.\n */\n mode?: 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst Modal = ({\n open = false,\n maskClosable,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n content,\n footer,\n container,\n children,\n okText,\n cancelText,\n onOk,\n onCancel,\n ...props\n}: Props) => {\n const { locale, defaultProps } = useConfig();\n const modalDefaults = defaultProps?.modal as\n Partial<Pick<Props, 'maskClosable'>> | undefined;\n // Explicit prop > `Config` default > built-in, matching Button/Tag.\n const resolvedMaskClosable =\n maskClosable ?? modalDefaults?.maskClosable ?? false;\n\n if (typeof window === 'undefined') {\n return null;\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(open: boolean) => {\n if (!open) {\n onCancel?.();\n }\n }}\n // antd's `maskClosable` is a root-level dismissal concern in Base UI:\n // blocking the outside (mask) press keeps the dialog open on backdrop\n // click while Escape still closes it, matching the previous behaviour.\n disablePointerDismissal={!resolvedMaskClosable}\n {...props}\n >\n <DialogContent\n className={cn(\n 'rounded-lg p-4 max-sm:max-w-[80%]',\n 'border-none outline-none',\n className,\n )}\n classNames={{\n ...classNames,\n mask: cn('bg-black/60', classNames?.mask),\n }}\n style={style}\n closable={closable}\n closeIcon={closeIcon}\n container={container}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\n *\n * Filed while `core/dialog` was still Radix-based; the linked fix is\n * Radix's, and the repo no longer depends on it. Revalidate against\n * Base UI's Dialog before acting on this — the bug may already be gone.\n * @see https://github.com/radix-ui/primitives/pull/3384\n **/}\n <DialogHeader\n className={cn(\n classNames?.header,\n !title && 'hidden',\n //\n )}\n >\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription className=\"hidden\" />\n </DialogHeader>\n <div className={cn('break-all', classNames?.body)}>\n {children ?? content}\n </div>\n {footer !== null && (\n <DialogFooter\n className={cn('flex-row justify-end gap-x-2', classNames?.footer)}\n >\n {footer || (\n <>\n <Button onClick={onOk}>\n {okText ?? locale.ok ?? DEFAULT_LOCALE.ok}\n </Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel}\n </Button>\n </>\n )}\n </DialogFooter>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nconst STATIC_ICONS = {\n info: <Info className=\"text-blue-400\" />,\n success: <Check className=\"text-green-400\" />,\n error: <OctagonX className=\"text-red-400\" />,\n warning: <OctagonAlert className=\"text-yellow-400\" />,\n confirm: <CircleQuestionMark />,\n};\n\nconst StaticModal = ({\n id,\n status,\n mode,\n title,\n content,\n okText,\n cancelText,\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps & { id: string }): React.ReactPortal | null => {\n const { locale } = useConfig();\n const [open, setOpen] = useState(true);\n const resolvedOkText = okText ?? locale.ok ?? DEFAULT_LOCALE.ok;\n const resolvedCancelText =\n cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel;\n // `confirm` is an interaction mode (two-button footer), not a status; the\n // semantic state comes from `status`.\n const isConfirm = mode === 'confirm';\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n modalStack.destroy(id);\n }, 200);\n };\n\n const footer = isConfirm ? (\n <div className=\"grid w-full grid-cols-5 gap-x-2\">\n <Button\n variant=\"outlined\"\n className=\"col-span-2\"\n onClick={() => closeModal(onCancel)}\n >\n {resolvedCancelText}\n </Button>\n <Button className=\"col-span-3\" onClick={() => closeModal(onOk)}>\n {resolvedOkText}\n </Button>\n </div>\n ) : (\n <Button\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {resolvedOkText}\n </Button>\n );\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <Modal\n open={open}\n footer={footer}\n className={cn(\n 'z-10000',\n 'box-content w-100',\n 'rounded-3xl p-4',\n 'gap-y-0',\n )}\n classNames={{\n mask: 'z-10000 bg-black/[.6]',\n body: cn(\n 'text-black-70 whitespace-pre-wrap text-center',\n content && 'mt-3',\n ),\n footer: 'mt-9',\n }}\n title={\n <p\n className={cn(\n 'text-center text-lg leading-normal whitespace-pre-wrap',\n 'flex items-center justify-center gap-x-2',\n //\n )}\n >\n {icon ||\n (isConfirm ? STATIC_ICONS.confirm : status && STATIC_ICONS[status])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onCancel)}\n {...props}\n >\n {content}\n </Modal>,\n modalStack.getRootElement(container)!,\n );\n};\n\n// No `role`/`aria-modal` here — this element is only a mount point for the\n// imperative stack, not the dialog itself. Base UI already renders its own\n// `role=\"dialog\"`/`aria-modal=\"true\"` on the actual `DialogContent` via\n// portal once a modal is open. Setting it here as well would (a) leave\n// `aria-modal=\"true\"` on the page permanently, even with zero modals open,\n// hiding the rest of the document from screen readers, and (b) duplicate\n// Base UI's own dialog role once one is open.\nconst modalStack: ImperativeStack<StaticProps> =\n createImperativeStack<StaticProps>({\n createRootElement: () => {\n const el = document.createElement('div');\n el.style.zIndex = '10000';\n el.style.position = 'absolute';\n return el;\n },\n StackItem: StaticModal,\n });\n\nModal.destroy = modalStack.destroy;\n\nModal.destroyAll = () => {\n modalStack.destroy();\n};\n\nModal.info = (props: StaticProps) =>\n modalStack.render({ status: 'info', ...props });\nModal.success = (props: StaticProps) =>\n modalStack.render({ status: 'success', ...props });\nModal.error = (props: StaticProps) =>\n modalStack.render({ status: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n modalStack.render({ status: 'warning', ...props });\n// `confirm` is a mode, not a status, so it rides its own `mode` axis rather\n// than `status`.\nModal.confirm = (props: StaticProps) =>\n modalStack.render({ mode: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"modal.mjs","names":["dialog"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\n\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { dialog } from '../../core';\nimport Button from '../atoms/button';\nimport {\n type ImperativeStack,\n createImperativeStack,\n isBrowser,\n} from './imperative-stack';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\nexport interface Props {\n open?: boolean;\n maskClosable?: boolean;\n closable?:\n | boolean\n | {\n closeIcon?: React.ReactNode;\n disabled?: boolean;\n };\n closeIcon?: React.ReactNode;\n title?: React.ReactNode;\n content?: React.ReactNode;\n footer?: React.ReactNode;\n className?: string;\n classNames?: {\n mask?: string;\n header?: string;\n body?: string;\n footer?: string;\n };\n style?: React.CSSProperties;\n okText?: string;\n cancelText?: string;\n container?: HTMLElement;\n children?: React.ReactNode;\n onOk?: () => void;\n onCancel?: () => void;\n}\n\ntype ModalStatus = 'info' | 'success' | 'error' | 'warning';\n\ninterface StaticProps extends Props {\n status?: ModalStatus;\n /**\n * Interaction mode set by `Modal.confirm()` to request the two-button\n * footer. `confirm` is a mode, not a status, so it rides its own axis rather\n * than `status` — call `Modal.confirm()` rather than setting this directly.\n */\n mode?: 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst Modal = ({\n open = false,\n maskClosable,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n content,\n footer,\n container,\n children,\n okText,\n cancelText,\n onOk,\n onCancel,\n ...props\n}: Props) => {\n const { locale, defaultProps } = useConfig();\n const modalDefaults = defaultProps?.modal as\n Partial<Pick<Props, 'maskClosable'>> | undefined;\n // Explicit prop > `Config` default > built-in, matching Button/Tag.\n const resolvedMaskClosable =\n maskClosable ?? modalDefaults?.maskClosable ?? false;\n\n if (typeof window === 'undefined') {\n return null;\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(open: boolean) => {\n if (!open) {\n onCancel?.();\n }\n }}\n // antd's `maskClosable` is a root-level dismissal concern in Base UI:\n // blocking the outside (mask) press keeps the dialog open on backdrop\n // click while Escape still closes it, matching the previous behaviour.\n disablePointerDismissal={!resolvedMaskClosable}\n {...props}\n >\n <DialogContent\n className={cn(\n 'rounded-lg p-4 max-sm:max-w-[80%]',\n 'border-none outline-none',\n className,\n )}\n classNames={{\n ...classNames,\n mask: cn('bg-black/60', classNames?.mask),\n }}\n style={style}\n closable={closable}\n closeIcon={closeIcon}\n container={container}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\n *\n * Filed while `core/dialog` was still Radix-based; the linked fix is\n * Radix's, and the repo no longer depends on it. Revalidate against\n * Base UI's Dialog before acting on this — the bug may already be gone.\n * @see https://github.com/radix-ui/primitives/pull/3384\n **/}\n <DialogHeader\n className={cn(\n classNames?.header,\n !title && 'hidden',\n //\n )}\n >\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription className=\"hidden\" />\n </DialogHeader>\n <div className={cn('break-all', classNames?.body)}>\n {children ?? content}\n </div>\n {footer !== null && (\n <DialogFooter\n className={cn('flex-row justify-end gap-x-2', classNames?.footer)}\n >\n {footer || (\n <>\n {/*\n * The confirming action is solid primary and the dismissing one\n * stays outlined, so the two read as different weights. Both\n * used to resolve to `outlined` — Button defaults to that\n * variant, so the unstyled OK button rendered identically to\n * the explicitly outlined Cancel beside it.\n */}\n <Button type=\"primary\" onClick={onOk}>\n {okText ?? locale.ok ?? DEFAULT_LOCALE.ok}\n </Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel}\n </Button>\n </>\n )}\n </DialogFooter>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nconst STATIC_ICONS = {\n info: <Info className=\"text-blue-400\" />,\n success: <Check className=\"text-green-400\" />,\n error: <OctagonX className=\"text-red-400\" />,\n warning: <OctagonAlert className=\"text-yellow-400\" />,\n confirm: <CircleQuestionMark />,\n};\n\nconst StaticModal = ({\n id,\n status,\n mode,\n title,\n content,\n okText,\n cancelText,\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps & { id: string }): React.ReactPortal | null => {\n const { locale } = useConfig();\n const [open, setOpen] = useState(true);\n const resolvedOkText = okText ?? locale.ok ?? DEFAULT_LOCALE.ok;\n const resolvedCancelText =\n cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel;\n // `confirm` is an interaction mode (two-button footer), not a status; the\n // semantic state comes from `status`.\n const isConfirm = mode === 'confirm';\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n modalStack.destroy(id);\n }, 200);\n };\n\n // Confirming action first, dismissing action second — the same order as the\n // controlled footer above, which used to run the other way round here and\n // put the two footers of one component in opposite orders.\n const footer = isConfirm ? (\n <div className=\"grid w-full grid-cols-5 gap-x-2\">\n <Button\n type=\"primary\"\n className=\"col-span-3\"\n onClick={() => closeModal(onOk)}\n >\n {resolvedOkText}\n </Button>\n <Button\n variant=\"outlined\"\n className=\"col-span-2\"\n onClick={() => closeModal(onCancel)}\n >\n {resolvedCancelText}\n </Button>\n </div>\n ) : (\n <Button\n type=\"primary\"\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {resolvedOkText}\n </Button>\n );\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <Modal\n open={open}\n footer={footer}\n className={cn(\n 'z-10000',\n 'box-content w-100',\n 'rounded-3xl p-4',\n 'gap-y-0',\n )}\n classNames={{\n mask: 'z-10000 bg-black/[.6]',\n body: cn(\n 'text-black-70 whitespace-pre-wrap text-center',\n content && 'mt-3',\n ),\n footer: 'mt-9',\n }}\n title={\n <p\n className={cn(\n 'text-center text-lg leading-normal whitespace-pre-wrap',\n 'flex items-center justify-center gap-x-2',\n //\n )}\n >\n {icon ||\n (isConfirm ? STATIC_ICONS.confirm : status && STATIC_ICONS[status])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onCancel)}\n {...props}\n >\n {content}\n </Modal>,\n modalStack.getRootElement(container)!,\n );\n};\n\n// No `role`/`aria-modal` here — this element is only a mount point for the\n// imperative stack, not the dialog itself. Base UI already renders its own\n// `role=\"dialog\"`/`aria-modal=\"true\"` on the actual `DialogContent` via\n// portal once a modal is open. Setting it here as well would (a) leave\n// `aria-modal=\"true\"` on the page permanently, even with zero modals open,\n// hiding the rest of the document from screen readers, and (b) duplicate\n// Base UI's own dialog role once one is open.\nconst modalStack: ImperativeStack<StaticProps> =\n createImperativeStack<StaticProps>({\n createRootElement: () => {\n const el = document.createElement('div');\n el.style.zIndex = '10000';\n el.style.position = 'absolute';\n return el;\n },\n StackItem: StaticModal,\n });\n\nModal.destroy = modalStack.destroy;\n\nModal.destroyAll = () => {\n modalStack.destroy();\n};\n\nModal.info = (props: StaticProps) =>\n modalStack.render({ status: 'info', ...props });\nModal.success = (props: StaticProps) =>\n modalStack.render({ status: 'success', ...props });\nModal.error = (props: StaticProps) =>\n modalStack.render({ status: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n modalStack.render({ status: 'warning', ...props });\n// `confirm` is a mode, not a status, so it rides its own `mode` axis rather\n// than `status`.\nModal.confirm = (props: StaticProps) =>\n modalStack.render({ mode: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":"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"}
|