@jbpark/ui-kit 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/atoms/popover.d.mts.map +1 -1
- package/dist/components/atoms/popover.mjs +71 -19
- package/dist/components/atoms/popover.mjs.map +1 -1
- package/dist/components/atoms/skeleton/button.d.mts +1 -1
- package/dist/components/atoms/skeleton/button.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/button.mjs +5 -2
- package/dist/components/atoms/skeleton/button.mjs.map +1 -1
- package/dist/components/atoms/skeleton/node.d.mts +1 -1
- package/dist/components/atoms/skeleton/node.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/node.mjs +5 -2
- package/dist/components/atoms/skeleton/node.mjs.map +1 -1
- package/dist/components/organisms/drawer.d.mts.map +1 -1
- package/dist/components/organisms/drawer.mjs +37 -13
- package/dist/components/organisms/drawer.mjs.map +1 -1
- package/dist/components/organisms/list/list.mjs +1 -6
- package/dist/components/organisms/list/list.mjs.map +1 -1
- package/dist/components/organisms/modal.d.mts +1 -0
- package/dist/components/organisms/modal.d.mts.map +1 -1
- package/dist/components/organisms/modal.mjs +13 -8
- package/dist/components/organisms/modal.mjs.map +1 -1
- package/dist/components/organisms/swiper/swiper.d.mts.map +1 -1
- package/dist/components/organisms/swiper/swiper.mjs +5 -1
- package/dist/components/organisms/swiper/swiper.mjs.map +1 -1
- package/dist/components/organisms/toast.d.mts.map +1 -1
- package/dist/components/organisms/toast.mjs +10 -3
- package/dist/components/organisms/toast.mjs.map +1 -1
- package/dist/core/badge.d.mts +1 -1
- package/dist/core/button.d.mts +2 -2
- package/dist/style.css +138 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";;;KASK,SAAA;AAAA,UAcY,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,SAAA,GAAY,SAAA;EACZ,OAAA,EAAS,KAAA,CAAM,SAAA;EACf,IAAA;EACA,WAAA;EACA,YAAA,IAAgB,IAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";;;KASK,SAAA;AAAA,UAcY,KAAA,SAAc,IAAA,CAC7B,KAAA,CAAM,wBAAA;EAGN,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,SAAA,GAAY,SAAA;EACZ,OAAA,EAAS,KAAA,CAAM,SAAA;EACf,IAAA;EACA,WAAA;EACA,YAAA,IAAgB,IAAA;AAAA;AAAA,cA6JZ,OAAA;EAAW,KAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA,QAAA;EAAA,IAAA,EAAA,KAAA;EAAA,WAAA;EAAA,YAAA;EAAA,GAAA;AAAA,GAUd,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -86,27 +86,79 @@ const fillColorBySide = {
|
|
|
86
86
|
left: "after:border-l-8 after:border-l-popover",
|
|
87
87
|
right: "after:border-r-8 after:border-r-popover"
|
|
88
88
|
};
|
|
89
|
-
const
|
|
90
|
-
top:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
const POSITION_CLASSES = {
|
|
90
|
+
top: {
|
|
91
|
+
start: {
|
|
92
|
+
wrapper: "top-full left-4",
|
|
93
|
+
before: "before:top-0 before:left-0",
|
|
94
|
+
after: "after:-top-px after:left-px"
|
|
95
|
+
},
|
|
96
|
+
center: {
|
|
97
|
+
wrapper: "top-full left-1/2 -translate-x-1/2",
|
|
98
|
+
before: "before:top-0 before:left-1/2 before:-translate-x-1/2",
|
|
99
|
+
after: "after:-top-px after:left-1/2 after:-translate-x-1/2"
|
|
100
|
+
},
|
|
101
|
+
end: {
|
|
102
|
+
wrapper: "top-full right-4",
|
|
103
|
+
before: "before:top-0 before:right-0",
|
|
104
|
+
after: "after:-top-px after:right-px"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
bottom: {
|
|
108
|
+
start: {
|
|
109
|
+
wrapper: "bottom-full left-4",
|
|
110
|
+
before: "before:bottom-0 before:left-0",
|
|
111
|
+
after: "after:-bottom-px after:left-px"
|
|
112
|
+
},
|
|
113
|
+
center: {
|
|
114
|
+
wrapper: "bottom-full left-1/2 -translate-x-1/2",
|
|
115
|
+
before: "before:bottom-0 before:left-1/2 before:-translate-x-1/2",
|
|
116
|
+
after: "after:-bottom-px after:left-1/2 after:-translate-x-1/2"
|
|
117
|
+
},
|
|
118
|
+
end: {
|
|
119
|
+
wrapper: "bottom-full right-4",
|
|
120
|
+
before: "before:bottom-0 before:right-0",
|
|
121
|
+
after: "after:-bottom-px after:right-px"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
left: {
|
|
125
|
+
start: {
|
|
126
|
+
wrapper: "left-full top-4",
|
|
127
|
+
before: "before:left-0 before:top-0",
|
|
128
|
+
after: "after:-left-px after:top-px"
|
|
129
|
+
},
|
|
130
|
+
center: {
|
|
131
|
+
wrapper: "left-full top-1/2 -translate-y-1/2",
|
|
132
|
+
before: "before:left-0 before:top-1/2 before:-translate-y-1/2",
|
|
133
|
+
after: "after:-left-px after:top-1/2 after:-translate-y-1/2"
|
|
134
|
+
},
|
|
135
|
+
end: {
|
|
136
|
+
wrapper: "left-full bottom-4",
|
|
137
|
+
before: "before:left-0 before:bottom-0",
|
|
138
|
+
after: "after:-left-px after:bottom-px"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
right: {
|
|
142
|
+
start: {
|
|
143
|
+
wrapper: "right-full top-4",
|
|
144
|
+
before: "before:right-0 before:top-0",
|
|
145
|
+
after: "after:-right-px after:top-px"
|
|
146
|
+
},
|
|
147
|
+
center: {
|
|
148
|
+
wrapper: "right-full top-1/2 -translate-y-1/2",
|
|
149
|
+
before: "before:right-0 before:top-1/2 before:-translate-y-1/2",
|
|
150
|
+
after: "after:-right-px after:top-1/2 after:-translate-y-1/2"
|
|
151
|
+
},
|
|
152
|
+
end: {
|
|
153
|
+
wrapper: "right-full bottom-4",
|
|
154
|
+
before: "before:right-0 before:bottom-0",
|
|
155
|
+
after: "after:-right-px after:bottom-px"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
102
158
|
};
|
|
103
159
|
const getArrowClassName = (side, align) => {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const positionAlign = alignEdge ? `${alignEdge}-4` : `${startEdgeByAxis[axis]}-1/2 -translate-${axis}-1/2`;
|
|
107
|
-
const beforeAlign = alignEdge ? `before:${alignEdge}-0` : `before:${startEdgeByAxis[axis]}-1/2 before:-translate-${axis}-1/2`;
|
|
108
|
-
const afterAlign = alignEdge ? `after:${alignEdge}-px` : `after:${startEdgeByAxis[axis]}-1/2 after:-translate-${axis}-1/2`;
|
|
109
|
-
return cn(`absolute ${positionAlign} ${side}-full`, beforeBase, `before:${side}-0`, beforeAlign, borderShapeBySide[side], borderColorBySide[side], afterBase, `after:-${side}-px`, afterAlign, fillShapeBySide[side], fillColorBySide[side]);
|
|
160
|
+
const { wrapper, before, after } = POSITION_CLASSES[side][align];
|
|
161
|
+
return cn("absolute", wrapper, beforeBase, before, borderShapeBySide[side], borderColorBySide[side], afterBase, after, fillShapeBySide[side], fillColorBySide[side]);
|
|
110
162
|
};
|
|
111
163
|
const Popover = ({ title, placement = "top", className, content, children, open: _open, defaultOpen, onOpenChange, ...props }) => {
|
|
112
164
|
const [open, setOpen] = useControllableState({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["import { useControllableState } from '@jbpark/use-hooks';\n\nimport { popover } from '@repo/ui/core';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Typography from './typography';\n\nconst { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover;\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\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\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\nconst beforeBase = 'before:content-[\"\"] before:absolute before:h-0 before:w-0';\nconst afterBase = 'after:content-[\"\"] after:absolute after:h-0 after:w-0';\n\nconst vBorderShape =\n 'before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent';\nconst hBorderShape =\n 'before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent';\nconst vFillShape =\n 'after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent';\nconst hFillShape =\n 'after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent';\n\n// Top/bottom placements draw a vertical-edge triangle (border-l/border-r) —\n// the arrow points up/down, so its left/right edges form the point. Left/\n// right placements draw the horizontal-edge equivalent.\nconst borderShapeBySide: Record<Side, string> = {\n top: vBorderShape,\n bottom: vBorderShape,\n left: hBorderShape,\n right: hBorderShape,\n};\nconst fillShapeBySide: Record<Side, string> = {\n top: vFillShape,\n bottom: vFillShape,\n left: hFillShape,\n right: hFillShape,\n};\nconst borderColorBySide: Record<Side, string> = {\n top: 'before:border-t-[9px] before:border-t-border',\n bottom: 'before:border-b-[9px] before:border-b-border',\n left: 'before:border-l-[9px] before:border-l-border',\n right: 'before:border-r-[9px] before:border-r-border',\n};\nconst fillColorBySide: Record<Side, string> = {\n top: 'after:border-t-8 after:border-t-popover',\n bottom: 'after:border-b-8 after:border-b-popover',\n left: 'after:border-l-8 after:border-l-popover',\n right: 'after:border-r-8 after:border-r-popover',\n};\n\n//
|
|
1
|
+
{"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["import { useControllableState } from '@jbpark/use-hooks';\n\nimport { popover } from '@repo/ui/core';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Typography from './typography';\n\nconst { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover;\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\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\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\nconst beforeBase = 'before:content-[\"\"] before:absolute before:h-0 before:w-0';\nconst afterBase = 'after:content-[\"\"] after:absolute after:h-0 after:w-0';\n\nconst vBorderShape =\n 'before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent';\nconst hBorderShape =\n 'before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent';\nconst vFillShape =\n 'after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent';\nconst hFillShape =\n 'after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent';\n\n// Top/bottom placements draw a vertical-edge triangle (border-l/border-r) —\n// the arrow points up/down, so its left/right edges form the point. Left/\n// right placements draw the horizontal-edge equivalent.\nconst borderShapeBySide: Record<Side, string> = {\n top: vBorderShape,\n bottom: vBorderShape,\n left: hBorderShape,\n right: hBorderShape,\n};\nconst fillShapeBySide: Record<Side, string> = {\n top: vFillShape,\n bottom: vFillShape,\n left: hFillShape,\n right: hFillShape,\n};\nconst borderColorBySide: Record<Side, string> = {\n top: 'before:border-t-[9px] before:border-t-border',\n bottom: 'before:border-b-[9px] before:border-b-border',\n left: 'before:border-l-[9px] before:border-l-border',\n right: 'before:border-r-[9px] before:border-r-border',\n};\nconst fillColorBySide: Record<Side, string> = {\n top: 'after:border-t-8 after:border-t-popover',\n bottom: 'after:border-b-8 after:border-b-popover',\n left: 'after:border-l-8 after:border-l-popover',\n right: 'after:border-r-8 after:border-r-popover',\n};\n\n// Tailwind v4 only extracts class candidates that appear as *literal*\n// strings in source — none of these ever do if built via\n// `` `${side}-full` `` style interpolation, so they'd silently never make\n// it into the generated CSS. This table exists purely so every class the\n// arrow can need appears literally somewhere in this file.\nconst POSITION_CLASSES: Record<\n Side,\n Record<Align, { wrapper: string; before: string; after: string }>\n> = {\n top: {\n start: {\n wrapper: 'top-full left-4',\n before: 'before:top-0 before:left-0',\n after: 'after:-top-px after:left-px',\n },\n center: {\n wrapper: 'top-full left-1/2 -translate-x-1/2',\n before: 'before:top-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-top-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'top-full right-4',\n before: 'before:top-0 before:right-0',\n after: 'after:-top-px after:right-px',\n },\n },\n bottom: {\n start: {\n wrapper: 'bottom-full left-4',\n before: 'before:bottom-0 before:left-0',\n after: 'after:-bottom-px after:left-px',\n },\n center: {\n wrapper: 'bottom-full left-1/2 -translate-x-1/2',\n before: 'before:bottom-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-bottom-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'bottom-full right-4',\n before: 'before:bottom-0 before:right-0',\n after: 'after:-bottom-px after:right-px',\n },\n },\n left: {\n start: {\n wrapper: 'left-full top-4',\n before: 'before:left-0 before:top-0',\n after: 'after:-left-px after:top-px',\n },\n center: {\n wrapper: 'left-full top-1/2 -translate-y-1/2',\n before: 'before:left-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-left-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'left-full bottom-4',\n before: 'before:left-0 before:bottom-0',\n after: 'after:-left-px after:bottom-px',\n },\n },\n right: {\n start: {\n wrapper: 'right-full top-4',\n before: 'before:right-0 before:top-0',\n after: 'after:-right-px after:top-px',\n },\n center: {\n wrapper: 'right-full top-1/2 -translate-y-1/2',\n before: 'before:right-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-right-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'right-full bottom-4',\n before: 'before:right-0 before:bottom-0',\n after: 'after:-right-px after:bottom-px',\n },\n },\n};\n\nconst getArrowClassName = (side: Side, align: Align) => {\n const { wrapper, before, after } = POSITION_CLASSES[side][align];\n\n return cn(\n 'absolute',\n wrapper,\n beforeBase,\n before,\n borderShapeBySide[side],\n borderColorBySide[side],\n afterBase,\n after,\n fillShapeBySide[side],\n fillColorBySide[side],\n );\n};\n\nconst Popover = ({\n title,\n placement = 'top',\n className,\n content,\n children,\n open: _open,\n defaultOpen,\n onOpenChange,\n ...props\n}: Props) => {\n const [open, setOpen] = useControllableState<boolean>({\n value: _open,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n const { side, align } = placementMap[placement];\n\n return (\n <CorePopover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n {...props}\n align={align}\n side={side}\n sideOffset={16}\n className={cn('relative w-auto', className)}\n >\n {renderConditional(title, v => (\n <Typography.Title level={6}>{v}</Typography.Title>\n ))}\n {content}\n <div className={getArrowClassName(side, align)} />\n </PopoverContent>\n </CorePopover>\n );\n};\n\nexport default Popover;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"mappings":";;;;cAIM,MAAA;EAAU,
|
|
1
|
+
{"version":3,"file":"button.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"mappings":";;;;cAIM,MAAA;EAAU,UAAA;EAAA,GAAA;AAAA,GAA0B,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -3,10 +3,13 @@ import Skeleton from "./skeleton.mjs";
|
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/components/atoms/skeleton/button.tsx
|
|
6
|
-
const Button = ({
|
|
6
|
+
const Button = ({ classNames, ...props }) => {
|
|
7
7
|
return /* @__PURE__ */ jsx(Skeleton, {
|
|
8
8
|
...props,
|
|
9
|
-
|
|
9
|
+
classNames: {
|
|
10
|
+
...classNames,
|
|
11
|
+
item: cn("h-9 w-15", "rounded-2xl", classNames?.item)
|
|
12
|
+
}
|
|
10
13
|
});
|
|
11
14
|
};
|
|
12
15
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Button = ({
|
|
1
|
+
{"version":3,"file":"button.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Button = ({ classNames, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n classNames={{\n ...classNames,\n item: cn(\n 'h-9 w-15',\n 'rounded-2xl',\n classNames?.item,\n //\n ),\n }}\n />\n );\n};\nexport default Button;\n"],"mappings":";;;;;AAIA,MAAM,UAAU,EAAE,YAAY,GAAG,YAA2B;AAC1D,QACE,oBAAC;EACC,GAAI;EACJ,YAAY;GACV,GAAG;GACH,MAAM,GACJ,YACA,eACA,YAAY,KAEb;GACF;GACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"mappings":";;;;cAIM,IAAA;EAAQ,
|
|
1
|
+
{"version":3,"file":"node.d.mts","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"mappings":";;;;cAIM,IAAA;EAAQ,UAAA;EAAA,GAAA;AAAA,GAA0B,KAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -3,11 +3,14 @@ import Skeleton from "./skeleton.mjs";
|
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/components/atoms/skeleton/node.tsx
|
|
6
|
-
const Node = ({
|
|
6
|
+
const Node = ({ classNames, ...props }) => {
|
|
7
7
|
return /* @__PURE__ */ jsx(Skeleton, {
|
|
8
8
|
...props,
|
|
9
9
|
avatar: false,
|
|
10
|
-
|
|
10
|
+
classNames: {
|
|
11
|
+
...classNames,
|
|
12
|
+
item: cn("h-50 w-full min-w-80", "rounded-3xl", classNames?.item)
|
|
13
|
+
}
|
|
11
14
|
});
|
|
12
15
|
};
|
|
13
16
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Node = ({
|
|
1
|
+
{"version":3,"file":"node.mjs","names":[],"sources":["../../../../src/components/atoms/skeleton/node.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Skeleton, { type Props as SkeletonProps } from './skeleton';\n\nconst Node = ({ classNames, ...props }: SkeletonProps) => {\n return (\n <Skeleton\n {...props}\n avatar={false}\n classNames={{\n ...classNames,\n item: cn(\n 'h-50 w-full min-w-80',\n 'rounded-3xl',\n classNames?.item,\n //\n ),\n }}\n />\n );\n};\nexport default Node;\n"],"mappings":";;;;;AAIA,MAAM,QAAQ,EAAE,YAAY,GAAG,YAA2B;AACxD,QACE,oBAAC;EACC,GAAI;EACJ,QAAQ;EACR,YAAY;GACV,GAAG;GACH,MAAM,GACJ,wBACA,eACA,YAAY,KAEb;GACF;GACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";;;
|
|
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"}
|
|
@@ -9,14 +9,30 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
|
|
10
10
|
//#region src/components/organisms/drawer.tsx
|
|
11
11
|
const { DrawerContent, Drawer: DrawerCore, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle } = drawer_exports;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const maskLessStates = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
const getMaskLessState = (doc) => {
|
|
14
|
+
let state = maskLessStates.get(doc);
|
|
15
|
+
if (!state) {
|
|
16
|
+
state = {
|
|
17
|
+
count: 0,
|
|
18
|
+
originalPointerEvents: null
|
|
19
|
+
};
|
|
20
|
+
maskLessStates.set(doc, state);
|
|
21
|
+
}
|
|
22
|
+
return state;
|
|
23
|
+
};
|
|
14
24
|
const SIZES = {
|
|
15
25
|
small: "30%",
|
|
16
26
|
medium: "50%",
|
|
17
27
|
large: "75%",
|
|
18
28
|
full: "90%"
|
|
19
29
|
};
|
|
30
|
+
const ROUNDED_CLASSES = {
|
|
31
|
+
top: "rounded-b-[30px]!",
|
|
32
|
+
bottom: "rounded-t-[30px]!",
|
|
33
|
+
left: "rounded-r-[30px]!",
|
|
34
|
+
right: "rounded-l-[30px]!"
|
|
35
|
+
};
|
|
20
36
|
const getSizeStyles = (direction, size) => {
|
|
21
37
|
const value = SIZES[size] || size;
|
|
22
38
|
return direction === "top" || direction === "bottom" ? { height: value } : { width: value };
|
|
@@ -24,20 +40,28 @@ const getSizeStyles = (direction, size) => {
|
|
|
24
40
|
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 }) => {
|
|
25
41
|
useEffect(() => {
|
|
26
42
|
if (!open || mask) return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
43
|
+
const targetDocument = container?.ownerDocument ?? document;
|
|
44
|
+
const targetWindow = targetDocument.defaultView ?? window;
|
|
45
|
+
const body = targetDocument.body;
|
|
46
|
+
const state = getMaskLessState(targetDocument);
|
|
47
|
+
if (state.count === 0) state.originalPointerEvents = body.style.pointerEvents;
|
|
48
|
+
state.count += 1;
|
|
49
|
+
const raf = targetWindow.requestAnimationFrame(() => {
|
|
50
|
+
body.style.pointerEvents = "auto";
|
|
31
51
|
});
|
|
32
52
|
return () => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
targetWindow.cancelAnimationFrame(raf);
|
|
54
|
+
state.count -= 1;
|
|
55
|
+
if (state.count === 0) {
|
|
56
|
+
body.style.pointerEvents = state.originalPointerEvents ?? "";
|
|
57
|
+
state.originalPointerEvents = null;
|
|
38
58
|
}
|
|
39
59
|
};
|
|
40
|
-
}, [
|
|
60
|
+
}, [
|
|
61
|
+
open,
|
|
62
|
+
mask,
|
|
63
|
+
container
|
|
64
|
+
]);
|
|
41
65
|
return /* @__PURE__ */ jsx(DrawerCore, {
|
|
42
66
|
open,
|
|
43
67
|
direction,
|
|
@@ -48,7 +72,7 @@ const Drawer = ({ open, title, extra, footer, closable = true, closeIcon, direct
|
|
|
48
72
|
},
|
|
49
73
|
...props,
|
|
50
74
|
children: /* @__PURE__ */ jsxs(DrawerContent, {
|
|
51
|
-
className: cn("border-none outline-none", rounded ?
|
|
75
|
+
className: cn("border-none outline-none", rounded ? ROUNDED_CLASSES[direction] : "rounded-none!", classNames?.content, className),
|
|
52
76
|
handlebar,
|
|
53
77
|
mask,
|
|
54
78
|
onPointerDownOutside: (event) => {
|
|
@@ -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// `
|
|
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"}
|
|
@@ -49,11 +49,6 @@ const List = ({ loading, loaderProps, loader, header, title, titleLevel = 2, emp
|
|
|
49
49
|
})
|
|
50
50
|
]
|
|
51
51
|
});
|
|
52
|
-
if (!data?.length && empty) return /* @__PURE__ */ jsx("div", {
|
|
53
|
-
className: cn(className),
|
|
54
|
-
...props,
|
|
55
|
-
children: empty
|
|
56
|
-
});
|
|
57
52
|
return /* @__PURE__ */ jsxs("div", {
|
|
58
53
|
className: cn(className),
|
|
59
54
|
...props,
|
|
@@ -71,7 +66,7 @@ const List = ({ loading, loaderProps, loader, header, title, titleLevel = 2, emp
|
|
|
71
66
|
role: "list",
|
|
72
67
|
className: cn("space-y-2", classNames?.body),
|
|
73
68
|
children: [
|
|
74
|
-
data?.map((item, i) =>
|
|
69
|
+
!data?.length && empty ? empty : data?.map((item, i) => /* @__PURE__ */ jsx(React.Fragment, { children: renderItem(item, i) }, itemKey ? itemKey(item, i) : i)),
|
|
75
70
|
scroll?.loading && (scroll?.loader ?? /* @__PURE__ */ jsx(Skeleton.Node, {
|
|
76
71
|
count: 10,
|
|
77
72
|
gap: 10,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.mjs","names":[],"sources":["../../../../src/components/organisms/list/list.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useRef } from 'react';\n\nimport { useIntersectionObserver } from '@jbpark/use-hooks';\n\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Skeleton from '../../atoms/skeleton';\nimport { Title } from '../../atoms/typography';\n\ninterface Props<T> extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title'\n> {\n loading?: boolean;\n loaderProps?: React.ComponentProps<typeof Skeleton>;\n loader?: React.ReactNode;\n title?: React.ReactNode;\n titleLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n header?: React.ReactNode;\n empty?: React.ReactNode;\n classNames?: {\n title?: string;\n header?: string;\n body?: string;\n };\n scroll?: {\n hasMore: boolean;\n loading: boolean;\n loader?: React.ReactNode;\n options?: IntersectionObserverInit;\n /**\n * Called when more items should be fetched. `List` tracks in-flight\n * requests via `loading` — the caller MUST flip `loading` back to\n * `false` when the fetch settles, including on failure/rejection.\n * If `loading` never becomes `false` again after a failed fetch,\n * `List` will stop calling `next()` for subsequent intersections.\n */\n next: () => void;\n };\n data?: T[];\n renderItem?: (item: T, index: number) => React.ReactNode;\n itemKey?: (item: T, index: number) => React.Key;\n}\n\nconst List = <T,>({\n loading,\n loaderProps,\n loader,\n header,\n title,\n titleLevel = 2,\n empty,\n scroll,\n data,\n className,\n classNames,\n renderItem = () => null,\n itemKey,\n ...props\n}: Props<T>) => {\n const [loaderRef, { isIntersecting }] = useIntersectionObserver({\n threshold: 0,\n root: null,\n rootMargin: '0px',\n ...scroll?.options,\n });\n\n // `scroll` is typically a new object identity every render, so this\n // effect re-runs often. Guard with a ref (updated synchronously, unlike\n // the `loading` prop which only reflects the caller's next state update)\n // to avoid firing `next()` again for the same in-flight request before\n // the caller's `loading` has had a chance to become true.\n const fetchingRef = useRef(false);\n\n useEffect(() => {\n if (!scroll) {\n return;\n }\n\n if (scroll.loading) {\n fetchingRef.current = false;\n return;\n }\n\n if (isIntersecting && scroll.hasMore && !fetchingRef.current) {\n fetchingRef.current = true;\n scroll.next();\n }\n }, [isIntersecting, scroll]);\n\n if (loading) {\n return (\n loader || (\n <div className={cn(className)} {...props}>\n <div className={cn(classNames?.title)}>{title && <Skeleton />}</div>\n <div className={cn(classNames?.header)}>\n {header && <Skeleton size=\"small\" />}\n </div>\n <div className={cn('space-y-2', classNames?.body)}>\n <Skeleton.Node count={10} gap={10} {...loaderProps} />\n </div>\n </div>\n )\n );\n }\n\n
|
|
1
|
+
{"version":3,"file":"list.mjs","names":[],"sources":["../../../../src/components/organisms/list/list.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useRef } from 'react';\n\nimport { useIntersectionObserver } from '@jbpark/use-hooks';\n\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Skeleton from '../../atoms/skeleton';\nimport { Title } from '../../atoms/typography';\n\ninterface Props<T> extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title'\n> {\n loading?: boolean;\n loaderProps?: React.ComponentProps<typeof Skeleton>;\n loader?: React.ReactNode;\n title?: React.ReactNode;\n titleLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n header?: React.ReactNode;\n empty?: React.ReactNode;\n classNames?: {\n title?: string;\n header?: string;\n body?: string;\n };\n scroll?: {\n hasMore: boolean;\n loading: boolean;\n loader?: React.ReactNode;\n options?: IntersectionObserverInit;\n /**\n * Called when more items should be fetched. `List` tracks in-flight\n * requests via `loading` — the caller MUST flip `loading` back to\n * `false` when the fetch settles, including on failure/rejection.\n * If `loading` never becomes `false` again after a failed fetch,\n * `List` will stop calling `next()` for subsequent intersections.\n */\n next: () => void;\n };\n data?: T[];\n renderItem?: (item: T, index: number) => React.ReactNode;\n itemKey?: (item: T, index: number) => React.Key;\n}\n\nconst List = <T,>({\n loading,\n loaderProps,\n loader,\n header,\n title,\n titleLevel = 2,\n empty,\n scroll,\n data,\n className,\n classNames,\n renderItem = () => null,\n itemKey,\n ...props\n}: Props<T>) => {\n const [loaderRef, { isIntersecting }] = useIntersectionObserver({\n threshold: 0,\n root: null,\n rootMargin: '0px',\n ...scroll?.options,\n });\n\n // `scroll` is typically a new object identity every render, so this\n // effect re-runs often. Guard with a ref (updated synchronously, unlike\n // the `loading` prop which only reflects the caller's next state update)\n // to avoid firing `next()` again for the same in-flight request before\n // the caller's `loading` has had a chance to become true.\n const fetchingRef = useRef(false);\n\n useEffect(() => {\n if (!scroll) {\n return;\n }\n\n if (scroll.loading) {\n fetchingRef.current = false;\n return;\n }\n\n if (isIntersecting && scroll.hasMore && !fetchingRef.current) {\n fetchingRef.current = true;\n scroll.next();\n }\n }, [isIntersecting, scroll]);\n\n if (loading) {\n return (\n loader || (\n <div className={cn(className)} {...props}>\n <div className={cn(classNames?.title)}>{title && <Skeleton />}</div>\n <div className={cn(classNames?.header)}>\n {header && <Skeleton size=\"small\" />}\n </div>\n <div className={cn('space-y-2', classNames?.body)}>\n <Skeleton.Node count={10} gap={10} {...loaderProps} />\n </div>\n </div>\n )\n );\n }\n\n return (\n <div\n className={cn(\n className,\n //\n )}\n {...props}\n >\n {renderConditional(title, v => (\n <Title\n level={titleLevel}\n className={cn(\n 'px-1.5 py-4',\n 'text-black-90 text-lg leading-5.75 font-bold',\n //\n )}\n >\n {v}\n </Title>\n ))}\n <div className={cn(classNames?.header)}>{header}</div>\n <div role=\"list\" className={cn('space-y-2', classNames?.body)}>\n {!data?.length && empty\n ? empty\n : data?.map((item, i) => (\n <React.Fragment key={itemKey ? itemKey(item, i) : i}>\n {renderItem(item, i)}\n </React.Fragment>\n ))}\n {scroll?.loading &&\n (scroll?.loader ?? (\n <Skeleton.Node count={10} gap={10} {...loaderProps} />\n ))}\n {scroll && <div ref={loaderRef} />}\n </div>\n </div>\n );\n};\n\nexport default List;\n"],"mappings":";;;;;;;;;;AA8CA,MAAM,QAAY,EAChB,SACA,aACA,QACA,QACA,OACA,aAAa,GACb,OACA,QACA,MACA,WACA,YACA,mBAAmB,MACnB,SACA,GAAG,YACW;CACd,MAAM,CAAC,WAAW,EAAE,oBAAoB,wBAAwB;EAC9D,WAAW;EACX,MAAM;EACN,YAAY;EACZ,GAAG,QAAQ;EACZ,CAAC;CAOF,MAAM,cAAc,OAAO,MAAM;AAEjC,iBAAgB;AACd,MAAI,CAAC,OACH;AAGF,MAAI,OAAO,SAAS;AAClB,eAAY,UAAU;AACtB;;AAGF,MAAI,kBAAkB,OAAO,WAAW,CAAC,YAAY,SAAS;AAC5D,eAAY,UAAU;AACtB,UAAO,MAAM;;IAEd,CAAC,gBAAgB,OAAO,CAAC;AAE5B,KAAI,QACF,QACE,UACE,qBAAC;EAAI,WAAW,GAAG,UAAU;EAAE,GAAI;;GACjC,oBAAC;IAAI,WAAW,GAAG,YAAY,MAAM;cAAG,SAAS,oBAAC,aAAW;KAAO;GACpE,oBAAC;IAAI,WAAW,GAAG,YAAY,OAAO;cACnC,UAAU,oBAAC,YAAS,MAAK,UAAU;KAChC;GACN,oBAAC;IAAI,WAAW,GAAG,aAAa,YAAY,KAAK;cAC/C,oBAAC,SAAS;KAAK,OAAO;KAAI,KAAK;KAAI,GAAI;MAAe;KAClD;;GACF;AAKZ,QACE,qBAAC;EACC,WAAW,GACT,UAED;EACD,GAAI;;GAEH,kBAAkB,QAAO,MACxB,oBAAC;IACC,OAAO;IACP,WAAW,GACT,eACA,+CAED;cAEA;KACK,CACR;GACF,oBAAC;IAAI,WAAW,GAAG,YAAY,OAAO;cAAG;KAAa;GACtD,qBAAC;IAAI,MAAK;IAAO,WAAW,GAAG,aAAa,YAAY,KAAK;;KAC1D,CAAC,MAAM,UAAU,QACd,QACA,MAAM,KAAK,MAAM,MACf,oBAAC,MAAM,sBACJ,WAAW,MAAM,EAAE,IADD,UAAU,QAAQ,MAAM,EAAE,GAAG,EAEjC,CACjB;KACL,QAAQ,YACN,QAAQ,UACP,oBAAC,SAAS;MAAK,OAAO;MAAI,KAAK;MAAI,GAAI;OAAe;KAEzD,UAAU,oBAAC,SAAI,KAAK,YAAa;;KAC9B;;GACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;;;UA6BU,KAAA;EACR,IAAA;EACA,YAAA;EACA,QAAA;IAGM,SAAA,GAAY,KAAA,CAAM,SAAA;IAClB,QAAA;EAAA;EAEN,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,OAAA,GAAU,KAAA,CAAM,SAAA;EAChB,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,UAAA;IACE,IAAA;IACA,MAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,MAAA;EACA,UAAA;EACA,SAAA,GAAY,WAAA;EACZ,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,IAAA;EACA,QAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,IAAA;EACA,EAAA;EACA,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,SAAA,GAAY,WAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;;;UA6BU,KAAA;EACR,IAAA;EACA,YAAA;EACA,QAAA;IAGM,SAAA,GAAY,KAAA,CAAM,SAAA;IAClB,QAAA;EAAA;EAEN,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,OAAA,GAAU,KAAA,CAAM,SAAA;EAChB,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,UAAA;IACE,IAAA;IACA,MAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,MAAA;EACA,UAAA;EACA,SAAA,GAAY,WAAA;EACZ,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,IAAA;EACA,QAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,IAAA;EACA,EAAA;EACA,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,SAAA,GAAY,WAAA;AAAA;AAAA,cAmDR,KAAA;EAAA;;;;;;;;;;;;;;;;;;KAkBH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cAgQa,WAAA;iBACG,WAAA;eAEF,WAAA;iBACE,WAAA;iBAEA,WAAA;AAAA"}
|
|
@@ -14,6 +14,7 @@ import { v4 } from "uuid";
|
|
|
14
14
|
const { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } = dialog_exports;
|
|
15
15
|
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
16
16
|
const containerStates = /* @__PURE__ */ new Map();
|
|
17
|
+
const modalRootElements = /* @__PURE__ */ new WeakMap();
|
|
17
18
|
const getContainerState = (container) => {
|
|
18
19
|
let state = containerStates.get(container);
|
|
19
20
|
if (!state) {
|
|
@@ -28,19 +29,17 @@ const getContainerState = (container) => {
|
|
|
28
29
|
const createModalRoot = (container) => {
|
|
29
30
|
if (!isBrowser) return null;
|
|
30
31
|
const targetContainer = container || document.body;
|
|
31
|
-
let rootEl =
|
|
32
|
+
let rootEl = modalRootElements.get(targetContainer);
|
|
32
33
|
if (!rootEl) {
|
|
33
34
|
rootEl = document.createElement("div");
|
|
34
|
-
rootEl.setAttribute("id", "modal-root");
|
|
35
|
-
rootEl.setAttribute("role", "dialog");
|
|
36
|
-
rootEl.setAttribute("aria-modal", "true");
|
|
37
35
|
rootEl.style.zIndex = "10000";
|
|
38
36
|
rootEl.style.position = "absolute";
|
|
39
37
|
targetContainer.appendChild(rootEl);
|
|
38
|
+
modalRootElements.set(targetContainer, rootEl);
|
|
40
39
|
}
|
|
41
40
|
return rootEl;
|
|
42
41
|
};
|
|
43
|
-
const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon, className, classNames, style, title, footer, container, children, okText = "OK", cancelText = "Cancel", onOk, onCancel, ...props }) => {
|
|
42
|
+
const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon, className, classNames, style, title, content, footer, container, children, okText = "OK", cancelText = "Cancel", onOk, onCancel, ...props }) => {
|
|
44
43
|
if (typeof window === "undefined") return null;
|
|
45
44
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
46
45
|
open,
|
|
@@ -68,7 +67,7 @@ const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon
|
|
|
68
67
|
}),
|
|
69
68
|
/* @__PURE__ */ jsx("div", {
|
|
70
69
|
className: cn("break-all", classNames?.body),
|
|
71
|
-
children
|
|
70
|
+
children: children ?? content
|
|
72
71
|
}),
|
|
73
72
|
footer !== null && /* @__PURE__ */ jsx(DialogFooter, {
|
|
74
73
|
className: cn("flex-row justify-end gap-x-2", classNames?.footer),
|
|
@@ -133,7 +132,7 @@ const StaticModal = ({ type, title, content, okText = "OK", cancelText = "Cancel
|
|
|
133
132
|
children: [icon || type && STATIC_ICONS[type], title]
|
|
134
133
|
}),
|
|
135
134
|
container,
|
|
136
|
-
onCancel: () => closeModal(
|
|
135
|
+
onCancel: () => closeModal(onCancel),
|
|
137
136
|
...props,
|
|
138
137
|
children: content
|
|
139
138
|
}), createModalRoot(container));
|
|
@@ -178,7 +177,11 @@ Modal.destroy = (id) => {
|
|
|
178
177
|
state.stack = [];
|
|
179
178
|
state.update?.();
|
|
180
179
|
});
|
|
181
|
-
modalRoots.forEach((root) =>
|
|
180
|
+
modalRoots.forEach((root, container) => {
|
|
181
|
+
root.unmount();
|
|
182
|
+
modalRootElements.get(container)?.remove();
|
|
183
|
+
modalRootElements.delete(container);
|
|
184
|
+
});
|
|
182
185
|
modalRoots.clear();
|
|
183
186
|
containerStates.clear();
|
|
184
187
|
return;
|
|
@@ -191,6 +194,8 @@ Modal.destroy = (id) => {
|
|
|
191
194
|
modalRoots.get(container)?.unmount();
|
|
192
195
|
modalRoots.delete(container);
|
|
193
196
|
containerStates.delete(container);
|
|
197
|
+
modalRootElements.get(container)?.remove();
|
|
198
|
+
modalRootElements.delete(container);
|
|
194
199
|
}
|
|
195
200
|
});
|
|
196
201
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.mjs","names":["dialog","uuid"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\nimport { v4 as uuid } from 'uuid';\n\nimport { dialog } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\ninterface 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\ninterface StaticProps extends Props {\n type?: 'info' | 'success' | 'error' | 'warning' | 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState = {\n stack: StaticProps[];\n update: (() => void) | null;\n};\n\nconst containerStates = new Map<HTMLElement, ContainerState>();\n\nconst getContainerState = (container: HTMLElement): ContainerState => {\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\nconst createModalRoot = (container?: HTMLElement) => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = targetContainer.querySelector(\n '#modal-root',\n ) as HTMLElement | null;\n\n if (!rootEl) {\n rootEl = document.createElement('div');\n rootEl.setAttribute('id', 'modal-root');\n rootEl.setAttribute('role', 'dialog');\n rootEl.setAttribute('aria-modal', 'true');\n rootEl.style.zIndex = '10000';\n rootEl.style.position = 'absolute';\n targetContainer.appendChild(rootEl);\n }\n\n return rootEl;\n};\n\nconst Modal = ({\n open = false,\n maskClosable = false,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n footer,\n container,\n children,\n okText = 'OK',\n cancelText = 'Cancel',\n onOk,\n onCancel,\n ...props\n}: Props) => {\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 {...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 onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\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)}>{children}</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}>{okText}</Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText}\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 type,\n title,\n content,\n okText = 'OK',\n cancelText = 'Cancel',\n id,\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps) => {\n const [open, setOpen] = useState(true);\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n Modal.destroy(id);\n }, 200);\n };\n\n const footer =\n type === 'confirm' ? (\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 {cancelText}\n </Button>\n <Button className=\"col-span-3\" onClick={() => closeModal(onOk)}>\n {okText}\n </Button>\n </div>\n ) : (\n <Button\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {okText}\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 || (type && STATIC_ICONS[type])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onOk)}\n {...props}\n >\n {content}\n </Modal>,\n createModalRoot(container)!,\n );\n};\n\nconst ModalStackRenderer = ({ 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 <StaticModal key={id} id={id} {...props} />\n ))}\n </>\n );\n};\n\nconst modalRoots = new Map<HTMLElement, Root>();\n\nconst renderModal = (props: StaticProps) => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = createModalRoot(targetContainer)!;\n\n if (!modalRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n modalRoots.set(targetContainer, root);\n root.render(<ModalStackRenderer 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\nModal.destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n modalRoots.forEach(root => root.unmount());\n modalRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(modal => modal.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(modal => modal.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n modalRoots.get(container)?.unmount();\n modalRoots.delete(container);\n containerStates.delete(container);\n }\n });\n};\n\nModal.destroyAll = () => {\n Modal.destroy();\n};\n\nModal.info = (props: StaticProps) => renderModal({ type: 'info', ...props });\nModal.success = (props: StaticProps) =>\n renderModal({ type: 'success', ...props });\nModal.error = (props: StaticProps) => renderModal({ type: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n renderModal({ type: 'warning', ...props });\nModal.confirm = (props: StaticProps) =>\n renderModal({ type: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"modal.mjs","names":["dialog","uuid"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\nimport { v4 as uuid } from 'uuid';\n\nimport { dialog } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\ninterface 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\ninterface StaticProps extends Props {\n type?: 'info' | 'success' | 'error' | 'warning' | 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState = {\n stack: StaticProps[];\n update: (() => void) | null;\n};\n\nconst containerStates = new Map<HTMLElement, ContainerState>();\nconst modalRootElements = new WeakMap<HTMLElement, HTMLElement>();\n\nconst getContainerState = (container: HTMLElement): ContainerState => {\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// No `role`/`aria-modal` here — this element is only a mount point for the\n// imperative stack, not the dialog itself. Radix 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// Radix's own dialog role once one is open.\nconst createModalRoot = (container?: HTMLElement) => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = modalRootElements.get(targetContainer);\n\n if (!rootEl) {\n rootEl = document.createElement('div');\n rootEl.style.zIndex = '10000';\n rootEl.style.position = 'absolute';\n targetContainer.appendChild(rootEl);\n modalRootElements.set(targetContainer, rootEl);\n }\n\n return rootEl;\n};\n\nconst Modal = ({\n open = false,\n maskClosable = false,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n content,\n footer,\n container,\n children,\n okText = 'OK',\n cancelText = 'Cancel',\n onOk,\n onCancel,\n ...props\n}: Props) => {\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 {...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 onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\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}>{okText}</Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText}\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 type,\n title,\n content,\n okText = 'OK',\n cancelText = 'Cancel',\n id,\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps) => {\n const [open, setOpen] = useState(true);\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n Modal.destroy(id);\n }, 200);\n };\n\n const footer =\n type === 'confirm' ? (\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 {cancelText}\n </Button>\n <Button className=\"col-span-3\" onClick={() => closeModal(onOk)}>\n {okText}\n </Button>\n </div>\n ) : (\n <Button\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {okText}\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 || (type && STATIC_ICONS[type])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onCancel)}\n {...props}\n >\n {content}\n </Modal>,\n createModalRoot(container)!,\n );\n};\n\nconst ModalStackRenderer = ({ 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 <StaticModal key={id} id={id} {...props} />\n ))}\n </>\n );\n};\n\nconst modalRoots = new Map<HTMLElement, Root>();\n\nconst renderModal = (props: StaticProps) => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = createModalRoot(targetContainer)!;\n\n if (!modalRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n modalRoots.set(targetContainer, root);\n root.render(<ModalStackRenderer 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\nModal.destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n modalRoots.forEach((root, container) => {\n root.unmount();\n modalRootElements.get(container)?.remove();\n modalRootElements.delete(container);\n });\n modalRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(modal => modal.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(modal => modal.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n modalRoots.get(container)?.unmount();\n modalRoots.delete(container);\n containerStates.delete(container);\n modalRootElements.get(container)?.remove();\n modalRootElements.delete(container);\n }\n });\n};\n\nModal.destroyAll = () => {\n Modal.destroy();\n};\n\nModal.info = (props: StaticProps) => renderModal({ type: 'info', ...props });\nModal.success = (props: StaticProps) =>\n renderModal({ type: 'success', ...props });\nModal.error = (props: StaticProps) => renderModal({ type: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n renderModal({ type: 'warning', ...props });\nModal.confirm = (props: StaticProps) =>\n renderModal({ type: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":";;;;;;;;;;;;;AAoBA,MAAM,EACJ,QACA,eACA,mBACA,cACA,cACA,gBACEA;AAsCJ,MAAM,YACJ,OAAO,WAAW,eAAe,OAAO,aAAa;AAOvD,MAAM,kCAAkB,IAAI,KAAkC;AAC9D,MAAM,oCAAoB,IAAI,SAAmC;AAEjE,MAAM,qBAAqB,cAA2C;CACpE,IAAI,QAAQ,gBAAgB,IAAI,UAAU;AAE1C,KAAI,CAAC,OAAO;AACV,UAAQ;GAAE,OAAO,EAAE;GAAE,QAAQ;GAAM;AACnC,kBAAgB,IAAI,WAAW,MAAM;;AAGvC,QAAO;;AAUT,MAAM,mBAAmB,cAA4B;AACnD,KAAI,CAAC,UACH,QAAO;CAGT,MAAM,kBAAkB,aAAa,SAAS;CAC9C,IAAI,SAAS,kBAAkB,IAAI,gBAAgB;AAEnD,KAAI,CAAC,QAAQ;AACX,WAAS,SAAS,cAAc,MAAM;AACtC,SAAO,MAAM,SAAS;AACtB,SAAO,MAAM,WAAW;AACxB,kBAAgB,YAAY,OAAO;AACnC,oBAAkB,IAAI,iBAAiB,OAAO;;AAGhD,QAAO;;AAGT,MAAM,SAAS,EACb,OAAO,OACP,eAAe,OACf,WAAW,OACX,WACA,WACA,YACA,OACA,OACA,SACA,QACA,WACA,UACA,SAAS,MACT,aAAa,UACb,MACA,UACA,GAAG,YACQ;AACX,KAAI,OAAO,WAAW,YACpB,QAAO;AAGT,QACE,oBAAC;EACO;EACN,eAAe,SAAkB;AAC/B,OAAI,CAAC,KACH,aAAY;;EAGhB,GAAI;YAEJ,qBAAC;GACC,WAAW,GACT,qCACA,4BACA,UACD;GACD,YAAY;IACV,GAAG;IACH,MAAM,GAAG,eAAe,YAAY,KAAK;IAC1C;GACM;GACG;GACC;GACA;GACX,uBAAsB,UAAS;AAC7B,QAAI,CAAC,aACH,OAAM,gBAAgB;;;IAQ1B,qBAAC;KACC,WAAW,GACT,YAAY,QACZ,CAAC,SAAS,SAEX;gBAED,oBAAC,yBAAa,QAAoB,EAClC,oBAAC,qBAAkB,WAAU,WAAW;MAC3B;IACf,oBAAC;KAAI,WAAW,GAAG,aAAa,YAAY,KAAK;eAC9C,YAAY;MACT;IACL,WAAW,QACV,oBAAC;KACC,WAAW,GAAG,gCAAgC,YAAY,OAAO;eAEhE,UACC,8CACE,oBAAC;MAAO,SAAS;gBAAO;OAAgB,EACxC,oBAAC;MAAO,SAAQ;MAAW,SAAS;gBACjC;OACM,IACR;MAEQ;;IAEH;GACT;;AAIb,MAAM,eAAe;CACnB,MAAM,oBAAC,QAAK,WAAU,kBAAkB;CACxC,SAAS,oBAAC,SAAM,WAAU,mBAAmB;CAC7C,OAAO,oBAAC,YAAS,WAAU,iBAAiB;CAC5C,SAAS,oBAAC,gBAAa,WAAU,oBAAoB;CACrD,SAAS,oBAAC,uBAAqB;CAChC;AAED,MAAM,eAAe,EACnB,MACA,OACA,SACA,SAAS,MACT,aAAa,UACb,IACA,WACA,MACA,MACA,UACA,GAAG,YACc;CACjB,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,cAAc,aAA0B;AAC5C,cAAY;AACZ,UAAQ,MAAM;AACd,mBAAiB;AACf,SAAM,QAAQ,GAAG;KAChB,IAAI;;CAGT,MAAM,SACJ,SAAS,YACP,qBAAC;EAAI,WAAU;aACb,oBAAC;GACC,SAAQ;GACR,WAAU;GACV,eAAe,WAAW,SAAS;aAElC;IACM,EACT,oBAAC;GAAO,WAAU;GAAa,eAAe,WAAW,KAAK;aAC3D;IACM;GACL,GAEN,oBAAC;EACC,WAAW,GACT,OAED;EACD,eAAe,WAAW,KAAK;YAE9B;GACM;AAGb,KAAI,CAAC,UACH,QAAO;AAGT,QAAO,aACL,oBAAC;EACO;EACE;EACR,WAAW,GACT,WACA,qBACA,mBACA,UACD;EACD,YAAY;GACV,MAAM;GACN,MAAM,GACJ,iDACA,WAAW,OACZ;GACD,QAAQ;GACT;EACD,OACE,qBAAC;GACC,WAAW,GACT,0DACA,2CAED;cAEA,QAAS,QAAQ,aAAa,OAC9B;IACC;EAEK;EACX,gBAAgB,WAAW,SAAS;EACpC,GAAI;YAEH;GACK,EACR,gBAAgB,UAAU,CAC3B;;AAGH,MAAM,sBAAsB,EAAE,gBAA4C;CACxE,MAAM,GAAG,eAAe,SAAS,EAAE,CAAC;AAEpC,iBAAgB;EACd,MAAM,QAAQ,kBAAkB,UAAU;AAC1C,QAAM,eAAe,YAAY,EAAE,CAAC;AACpC,eAAa;AACX,SAAM,SAAS;;IAEhB,CAAC,UAAU,CAAC;CAEf,MAAM,EAAE,UAAU,kBAAkB,UAAU;AAE9C,QACE,4CACG,MAAM,KAAK,EAAE,IAAI,GAAG,YACnB,oBAAC;EAAyB;EAAI,GAAI;IAAhB,GAAyB,CAC3C,GACD;;AAIP,MAAM,6BAAa,IAAI,KAAwB;AAE/C,MAAM,eAAe,UAAuB;AAC1C,KAAI,CAAC,UACH;CAGF,MAAM,kBAAkB,MAAM,aAAa,SAAS;CACpD,MAAM,cAAc,gBAAgB,gBAAgB;AAEpD,KAAI,CAAC,WAAW,IAAI,gBAAgB,EAAE;EACpC,MAAM,OAAO,WAAW,YAAY;AACpC,aAAW,IAAI,iBAAiB,KAAK;AACrC,OAAK,OAAO,oBAAC,sBAAmB,WAAW,kBAAmB,CAAC;;CAGjE,MAAM,QAAQ,kBAAkB,gBAAgB;CAChD,MAAM,KAAK,MAAM,MAAMC,IAAM;AAC7B,OAAM,MAAM,KAAK;EAAE,GAAG;EAAO;EAAI,CAAC;AAClC,OAAM,UAAU;AAEhB,QAAO;;AAGT,MAAM,WAAW,OAAgB;AAC/B,KAAI,CAAC,IAAI;AACP,kBAAgB,SAAQ,UAAS;AAC/B,SAAM,QAAQ,EAAE;AAChB,SAAM,UAAU;IAChB;AACF,aAAW,SAAS,MAAM,cAAc;AACtC,QAAK,SAAS;AACd,qBAAkB,IAAI,UAAU,EAAE,QAAQ;AAC1C,qBAAkB,OAAO,UAAU;IACnC;AACF,aAAW,OAAO;AAClB,kBAAgB,OAAO;AACvB;;AAGF,iBAAgB,SAAS,OAAO,cAAc;AAC5C,MAAI,CAAC,MAAM,MAAM,MAAK,UAAS,MAAM,OAAO,GAAG,CAC7C;AAGF,QAAM,QAAQ,MAAM,MAAM,QAAO,UAAS,MAAM,OAAO,GAAG;AAC1D,QAAM,UAAU;AAEhB,MAAI,CAAC,MAAM,MAAM,QAAQ;AACvB,cAAW,IAAI,UAAU,EAAE,SAAS;AACpC,cAAW,OAAO,UAAU;AAC5B,mBAAgB,OAAO,UAAU;AACjC,qBAAkB,IAAI,UAAU,EAAE,QAAQ;AAC1C,qBAAkB,OAAO,UAAU;;GAErC;;AAGJ,MAAM,mBAAmB;AACvB,OAAM,SAAS;;AAGjB,MAAM,QAAQ,UAAuB,YAAY;CAAE,MAAM;CAAQ,GAAG;CAAO,CAAC;AAC5E,MAAM,WAAW,UACf,YAAY;CAAE,MAAM;CAAW,GAAG;CAAO,CAAC;AAC5C,MAAM,SAAS,UAAuB,YAAY;CAAE,MAAM;CAAS,GAAG;CAAO,CAAC;AAC9E,MAAM,WAAW,UACf,YAAY;CAAE,MAAM;CAAW,GAAG;CAAO,CAAC;AAC5C,MAAM,WAAW,UACf,YAAY;CAAE,MAAM;CAAW,GAAG;CAAO,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swiper.d.mts","names":[],"sources":["../../../../src/components/organisms/swiper/swiper.tsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"swiper.d.mts","names":[],"sources":["../../../../src/components/organisms/swiper/swiper.tsx"],"mappings":";;;;;;UA+BU,KAAA,YAAiB,WAAA;EACzB,OAAA;EACA,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,gBAAA;EACA,OAAA,GAAU,aAAA;EAiBwB;;;;;;;;;;;;;;EAFlC,OAAA,GAAU,YAAA;EACV,IAAA,EAAM,CAAA;EACN,UAAA,CAAW,IAAA,EAAM,CAAA,EAAG,GAAA,WAAc,KAAA,CAAM,SAAA;AAAA;AAAA,cAGpC,QAAA;EAAc,OAAA;EAAA,MAAA;EAAA,OAAA;EAAA,OAAA;EAAA,IAAA;EAAA,KAAA;EAAA,UAAA;EAAA,gBAAA;EAAA,GAAA;AAAA,GAUjB,KAAA,CAAM,CAAA,MAAE,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../../utils.mjs";
|
|
4
4
|
import Spin from "../../atoms/spin.mjs";
|
|
5
|
+
import { cloneElement, isValidElement } from "react";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
6
7
|
import { Swiper } from "swiper/react";
|
|
7
8
|
import "swiper/css";
|
|
@@ -41,7 +42,10 @@ const Swiper$1 = ({ loading, loader, options = {}, modules = [], data = [], styl
|
|
|
41
42
|
...style
|
|
42
43
|
},
|
|
43
44
|
...props,
|
|
44
|
-
children: data.map((item, i) =>
|
|
45
|
+
children: data.map((item, i) => {
|
|
46
|
+
const node = renderItem(item, i);
|
|
47
|
+
return isValidElement(node) && node.key == null ? cloneElement(node, { key: i }) : node;
|
|
48
|
+
})
|
|
45
49
|
});
|
|
46
50
|
};
|
|
47
51
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swiper.mjs","names":["Swiper","SwiperCore"],"sources":["../../../../src/components/organisms/swiper/swiper.tsx"],"sourcesContent":["'use client';\n\nimport { Swiper as SwiperCore, SwiperProps } from 'swiper/react';\nimport { SwiperModule, SwiperOptions } from 'swiper/types';\n\nimport { cn } from '@repo/ui/utils';\n\nimport 'swiper/css';\n\nimport { Spin } from '../../atoms';\n\n/**\n * Baseline Swiper options. `navigation` / `autoplay` are inert unless the\n * matching modules are passed through the `modules` prop — see the README next\n * to this file.\n */\nexport const initialOptions: SwiperOptions = {\n loop: false,\n spaceBetween: 8,\n slidesPerView: 'auto',\n navigation: false,\n autoplay: {\n delay: 2500,\n disableOnInteraction: false,\n },\n};\n\nconst initialStyle = { width: '100%', maxWidth: '100vw', overflow: 'hidden' };\n\ninterface Props<T> extends SwiperProps {\n loading?: boolean;\n loader?: React.ReactNode;\n loadingClassName?: string;\n options?: SwiperOptions;\n /**\n * Swiper feature modules to activate. Nothing is bundled by default — import\n * the modules you need from `swiper/modules` together with their stylesheets\n * (`swiper/css/<module>`) and pass them here.\n *\n * @example\n * import { Autoplay, Navigation } from 'swiper/modules';\n * import 'swiper/css/autoplay';\n * import 'swiper/css/navigation';\n *\n * <Swiper modules={[Autoplay, Navigation]} ... />\n *\n * @default []\n */\n modules?: SwiperModule[];\n data: T[];\n renderItem(item: T, key: number): React.ReactNode;\n}\n\nconst Swiper = <T,>({\n loading,\n loader,\n options = {},\n modules = [],\n data = [],\n style,\n renderItem,\n loadingClassName,\n ...props\n}: Props<T>) => {\n if (loading) {\n return (\n <div className={cn('h-32', loadingClassName)}>\n {loader || <Spin spinning />}\n </div>\n );\n }\n\n return (\n <SwiperCore\n modules={modules}\n {...initialOptions}\n {...options}\n style={{ ...initialStyle, ...style }}\n {...props}\n >\n {data.map((item: T, i) => renderItem(item, i))}\n </SwiperCore>\n );\n};\n\nexport default Swiper;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"swiper.mjs","names":["Swiper","SwiperCore"],"sources":["../../../../src/components/organisms/swiper/swiper.tsx"],"sourcesContent":["'use client';\n\nimport { cloneElement, isValidElement } from 'react';\n\nimport { Swiper as SwiperCore, SwiperProps } from 'swiper/react';\nimport { SwiperModule, SwiperOptions } from 'swiper/types';\n\nimport { cn } from '@repo/ui/utils';\n\nimport 'swiper/css';\n\nimport { Spin } from '../../atoms';\n\n/**\n * Baseline Swiper options. `navigation` / `autoplay` are inert unless the\n * matching modules are passed through the `modules` prop — see the README next\n * to this file.\n */\nexport const initialOptions: SwiperOptions = {\n loop: false,\n spaceBetween: 8,\n slidesPerView: 'auto',\n navigation: false,\n autoplay: {\n delay: 2500,\n disableOnInteraction: false,\n },\n};\n\nconst initialStyle = { width: '100%', maxWidth: '100vw', overflow: 'hidden' };\n\ninterface Props<T> extends SwiperProps {\n loading?: boolean;\n loader?: React.ReactNode;\n loadingClassName?: string;\n options?: SwiperOptions;\n /**\n * Swiper feature modules to activate. Nothing is bundled by default — import\n * the modules you need from `swiper/modules` together with their stylesheets\n * (`swiper/css/<module>`) and pass them here.\n *\n * @example\n * import { Autoplay, Navigation } from 'swiper/modules';\n * import 'swiper/css/autoplay';\n * import 'swiper/css/navigation';\n *\n * <Swiper modules={[Autoplay, Navigation]} ... />\n *\n * @default []\n */\n modules?: SwiperModule[];\n data: T[];\n renderItem(item: T, key: number): React.ReactNode;\n}\n\nconst Swiper = <T,>({\n loading,\n loader,\n options = {},\n modules = [],\n data = [],\n style,\n renderItem,\n loadingClassName,\n ...props\n}: Props<T>) => {\n if (loading) {\n return (\n <div className={cn('h-32', loadingClassName)}>\n {loader || <Spin spinning />}\n </div>\n );\n }\n\n return (\n <SwiperCore\n modules={modules}\n {...initialOptions}\n {...options}\n style={{ ...initialStyle, ...style }}\n {...props}\n >\n {data.map((item: T, i) => {\n const node = renderItem(item, i);\n // Fall back to an index key only when the consumer's renderItem\n // didn't already set one — cloning (rather than wrapping in a\n // Fragment) keeps the returned element a direct child of\n // SwiperCore, which swiper/react's slide detection relies on.\n return isValidElement(node) && node.key == null\n ? cloneElement(node, { key: i })\n : node;\n })}\n </SwiperCore>\n );\n};\n\nexport default Swiper;\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,iBAAgC;CAC3C,MAAM;CACN,cAAc;CACd,eAAe;CACf,YAAY;CACZ,UAAU;EACR,OAAO;EACP,sBAAsB;EACvB;CACF;AAED,MAAM,eAAe;CAAE,OAAO;CAAQ,UAAU;CAAS,UAAU;CAAU;AA0B7E,MAAMA,YAAc,EAClB,SACA,QACA,UAAU,EAAE,EACZ,UAAU,EAAE,EACZ,OAAO,EAAE,EACT,OACA,YACA,kBACA,GAAG,YACW;AACd,KAAI,QACF,QACE,oBAAC;EAAI,WAAW,GAAG,QAAQ,iBAAiB;YACzC,UAAU,oBAAC,QAAK,iBAAW;GACxB;AAIV,QACE,oBAACC;EACU;EACT,GAAI;EACJ,GAAI;EACJ,OAAO;GAAE,GAAG;GAAc,GAAG;GAAO;EACpC,GAAI;YAEH,KAAK,KAAK,MAAS,MAAM;GACxB,MAAM,OAAO,WAAW,MAAM,EAAE;AAKhC,UAAO,eAAe,KAAK,IAAI,KAAK,OAAO,OACvC,aAAa,MAAM,EAAE,KAAK,GAAG,CAAC,GAC9B;IACJ;GACS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.d.mts","names":[],"sources":["../../../src/components/organisms/toast.tsx"],"mappings":";;;KAcK,SAAA;AAAA,UAEY,KAAA;EACf,IAAA,GAAO,SAAA;EACP,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,WAAA,GAAc,KAAA,CAAM,SAAA;EACpB,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,QAAA;EACA,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,EAAA;EACA,QAAA;EACA,SAAA,GAAY,WAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"toast.d.mts","names":[],"sources":["../../../src/components/organisms/toast.tsx"],"mappings":";;;KAcK,SAAA;AAAA,UAEY,KAAA;EACf,IAAA,GAAO,SAAA;EACP,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,WAAA,GAAc,KAAA,CAAM,SAAA;EACpB,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,QAAA;EACA,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,EAAA;EACA,QAAA;EACA,SAAA,GAAY,WAAA;AAAA;AAAA,cA4DR,KAAA;EAAA;;;;;;;;;KASH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cAiKa,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEtB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;eAE3B,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEvB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;AAAA;AAAA,KAR5C,cAAA,GAAiB,IAAA,CAAK,WAAA"}
|
|
@@ -13,6 +13,7 @@ import { v4 } from "uuid";
|
|
|
13
13
|
//#region src/components/organisms/toast.tsx
|
|
14
14
|
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
15
15
|
const containerStates = /* @__PURE__ */ new Map();
|
|
16
|
+
const toastRootElements = /* @__PURE__ */ new WeakMap();
|
|
16
17
|
const getContainerState = (container) => {
|
|
17
18
|
let state = containerStates.get(container);
|
|
18
19
|
if (!state) {
|
|
@@ -27,10 +28,9 @@ const getContainerState = (container) => {
|
|
|
27
28
|
const createToastRoot = (container) => {
|
|
28
29
|
if (!isBrowser) return null;
|
|
29
30
|
const targetContainer = container || document.body;
|
|
30
|
-
let rootEl =
|
|
31
|
+
let rootEl = toastRootElements.get(targetContainer);
|
|
31
32
|
if (!rootEl) {
|
|
32
33
|
rootEl = document.createElement("div");
|
|
33
|
-
rootEl.setAttribute("id", "toast-root");
|
|
34
34
|
rootEl.setAttribute("role", "region");
|
|
35
35
|
rootEl.setAttribute("aria-label", "Notifications");
|
|
36
36
|
rootEl.style.zIndex = "10000";
|
|
@@ -43,6 +43,7 @@ const createToastRoot = (container) => {
|
|
|
43
43
|
rootEl.style.padding = "16px";
|
|
44
44
|
rootEl.style.pointerEvents = "none";
|
|
45
45
|
targetContainer.appendChild(rootEl);
|
|
46
|
+
toastRootElements.set(targetContainer, rootEl);
|
|
46
47
|
}
|
|
47
48
|
return rootEl;
|
|
48
49
|
};
|
|
@@ -149,7 +150,11 @@ Toast.destroy = (id) => {
|
|
|
149
150
|
state.stack = [];
|
|
150
151
|
state.update?.();
|
|
151
152
|
});
|
|
152
|
-
toastRoots.forEach((root) =>
|
|
153
|
+
toastRoots.forEach((root, container) => {
|
|
154
|
+
root.unmount();
|
|
155
|
+
toastRootElements.get(container)?.remove();
|
|
156
|
+
toastRootElements.delete(container);
|
|
157
|
+
});
|
|
153
158
|
toastRoots.clear();
|
|
154
159
|
containerStates.clear();
|
|
155
160
|
return;
|
|
@@ -162,6 +167,8 @@ Toast.destroy = (id) => {
|
|
|
162
167
|
toastRoots.get(container)?.unmount();
|
|
163
168
|
toastRoots.delete(container);
|
|
164
169
|
containerStates.delete(container);
|
|
170
|
+
toastRootElements.get(container)?.remove();
|
|
171
|
+
toastRootElements.delete(container);
|
|
165
172
|
}
|
|
166
173
|
});
|
|
167
174
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.mjs","names":["uuid"],"sources":["../../../src/components/organisms/toast.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport { useTimeout } from '@jbpark/use-hooks';\nimport { Check, Info, OctagonAlert, OctagonX, X } from 'lucide-react';\nimport { v4 as uuid } from 'uuid';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\ntype ToastType = 'info' | 'success' | 'error' | 'warning';\n\nexport interface Props {\n type?: ToastType;\n title: React.ReactNode;\n description?: React.ReactNode;\n icon?: React.ReactNode;\n closable?: boolean;\n action?: React.ReactNode;\n className?: string;\n onClose?: () => void;\n}\n\ninterface StaticProps extends Props {\n id?: string;\n duration?: number;\n container?: HTMLElement;\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState = {\n stack: StaticProps[];\n update: (() => void) | null;\n};\n\nconst containerStates = new Map<HTMLElement, ContainerState>();\n\nconst getContainerState = (container: HTMLElement): ContainerState => {\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\nconst createToastRoot = (container?: HTMLElement) => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = targetContainer.querySelector(\n '#toast-root',\n ) as HTMLElement | null;\n\n if (!rootEl) {\n rootEl = document.createElement('div');\n rootEl.setAttribute('id', 'toast-root');\n rootEl.setAttribute('role', 'region');\n rootEl.setAttribute('aria-label', 'Notifications');\n rootEl.style.zIndex = '10000';\n rootEl.style.position = 'fixed';\n rootEl.style.right = '0';\n rootEl.style.bottom = '0';\n rootEl.style.display = 'flex';\n rootEl.style.flexDirection = 'column-reverse';\n rootEl.style.gap = '8px';\n rootEl.style.padding = '16px';\n rootEl.style.pointerEvents = 'none';\n targetContainer.appendChild(rootEl);\n }\n\n return rootEl;\n};\n\nconst TYPE_ICONS: Record<ToastType, React.ReactNode> = {\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};\n\nconst Toast = ({\n type,\n title,\n description,\n icon,\n closable = true,\n action,\n className,\n onClose,\n}: Props) => {\n return (\n <div\n role=\"status\"\n className={cn(\n 'pointer-events-auto flex w-80 items-start gap-3 rounded-lg',\n 'bg-background text-foreground border p-4 shadow-lg',\n className,\n //\n )}\n >\n {(icon || type) && (\n <div className=\"mt-0.5 shrink-0 [&_svg]:size-5\">\n {icon || (type && TYPE_ICONS[type])}\n </div>\n )}\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-sm font-medium\">{title}</p>\n {description && (\n <p className=\"text-muted-foreground text-sm\">{description}</p>\n )}\n {action && <div className=\"pt-1\">{action}</div>}\n </div>\n {closable && (\n <Button\n type=\"text\"\n shape=\"circle\"\n size=\"small\"\n aria-label=\"Close\"\n icon={<X />}\n onClick={onClose}\n />\n )}\n </div>\n );\n};\n\nconst DEFAULT_DURATION = 4000;\n\nconst StaticToast = ({\n id,\n duration = DEFAULT_DURATION,\n container,\n onClose,\n ...props\n}: StaticProps) => {\n const [visible, setVisible] = useState(true);\n\n const close = () => {\n onClose?.();\n setVisible(false);\n setTimeout(() => {\n Toast.destroy(id);\n }, 200);\n };\n\n useTimeout(close, duration || null);\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <div\n className={cn(\n 'transition-all duration-200',\n visible ? 'opacity-100' : 'translate-x-2 opacity-0',\n )}\n >\n <Toast {...props} onClose={close} />\n </div>,\n createToastRoot(container)!,\n );\n};\n\nconst ToastStackRenderer = ({ 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 <StaticToast key={id} id={id} {...props} />\n ))}\n </>\n );\n};\n\nconst toastRoots = new Map<HTMLElement, Root>();\n\nconst renderToast = (props: StaticProps) => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = createToastRoot(targetContainer)!;\n\n if (!toastRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n toastRoots.set(targetContainer, root);\n root.render(<ToastStackRenderer 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\nToast.destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n toastRoots.forEach(root => root.unmount());\n toastRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(toast => toast.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(toast => toast.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n toastRoots.get(container)?.unmount();\n toastRoots.delete(container);\n containerStates.delete(container);\n }\n });\n};\n\nToast.destroyAll = () => {\n Toast.destroy();\n};\n\ntype TriggerOptions = Omit<StaticProps, 'type' | 'title'>;\n\nToast.info = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'info', title, ...props });\nToast.success = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'success', title, ...props });\nToast.error = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'error', title, ...props });\nToast.warning = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'warning', title, ...props });\n\nexport default Toast;\nexport type { StaticProps as ToastOptions };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toast.mjs","names":["uuid"],"sources":["../../../src/components/organisms/toast.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport { useTimeout } from '@jbpark/use-hooks';\nimport { Check, Info, OctagonAlert, OctagonX, X } from 'lucide-react';\nimport { v4 as uuid } from 'uuid';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\ntype ToastType = 'info' | 'success' | 'error' | 'warning';\n\nexport interface Props {\n type?: ToastType;\n title: React.ReactNode;\n description?: React.ReactNode;\n icon?: React.ReactNode;\n closable?: boolean;\n action?: React.ReactNode;\n className?: string;\n onClose?: () => void;\n}\n\ninterface StaticProps extends Props {\n id?: string;\n duration?: number;\n container?: HTMLElement;\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState = {\n stack: StaticProps[];\n update: (() => void) | null;\n};\n\nconst containerStates = new Map<HTMLElement, ContainerState>();\nconst toastRootElements = new WeakMap<HTMLElement, HTMLElement>();\n\nconst getContainerState = (container: HTMLElement): ContainerState => {\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\nconst createToastRoot = (container?: HTMLElement) => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = toastRootElements.get(targetContainer);\n\n if (!rootEl) {\n rootEl = document.createElement('div');\n rootEl.setAttribute('role', 'region');\n rootEl.setAttribute('aria-label', 'Notifications');\n rootEl.style.zIndex = '10000';\n rootEl.style.position = 'fixed';\n rootEl.style.right = '0';\n rootEl.style.bottom = '0';\n rootEl.style.display = 'flex';\n rootEl.style.flexDirection = 'column-reverse';\n rootEl.style.gap = '8px';\n rootEl.style.padding = '16px';\n rootEl.style.pointerEvents = 'none';\n targetContainer.appendChild(rootEl);\n toastRootElements.set(targetContainer, rootEl);\n }\n\n return rootEl;\n};\n\nconst TYPE_ICONS: Record<ToastType, React.ReactNode> = {\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};\n\nconst Toast = ({\n type,\n title,\n description,\n icon,\n closable = true,\n action,\n className,\n onClose,\n}: Props) => {\n return (\n <div\n role=\"status\"\n className={cn(\n 'pointer-events-auto flex w-80 items-start gap-3 rounded-lg',\n 'bg-background text-foreground border p-4 shadow-lg',\n className,\n //\n )}\n >\n {(icon || type) && (\n <div className=\"mt-0.5 shrink-0 [&_svg]:size-5\">\n {icon || (type && TYPE_ICONS[type])}\n </div>\n )}\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-sm font-medium\">{title}</p>\n {description && (\n <p className=\"text-muted-foreground text-sm\">{description}</p>\n )}\n {action && <div className=\"pt-1\">{action}</div>}\n </div>\n {closable && (\n <Button\n type=\"text\"\n shape=\"circle\"\n size=\"small\"\n aria-label=\"Close\"\n icon={<X />}\n onClick={onClose}\n />\n )}\n </div>\n );\n};\n\nconst DEFAULT_DURATION = 4000;\n\nconst StaticToast = ({\n id,\n duration = DEFAULT_DURATION,\n container,\n onClose,\n ...props\n}: StaticProps) => {\n const [visible, setVisible] = useState(true);\n\n const close = () => {\n onClose?.();\n setVisible(false);\n setTimeout(() => {\n Toast.destroy(id);\n }, 200);\n };\n\n useTimeout(close, duration || null);\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <div\n className={cn(\n 'transition-all duration-200',\n visible ? 'opacity-100' : 'translate-x-2 opacity-0',\n )}\n >\n <Toast {...props} onClose={close} />\n </div>,\n createToastRoot(container)!,\n );\n};\n\nconst ToastStackRenderer = ({ 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 <StaticToast key={id} id={id} {...props} />\n ))}\n </>\n );\n};\n\nconst toastRoots = new Map<HTMLElement, Root>();\n\nconst renderToast = (props: StaticProps) => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = createToastRoot(targetContainer)!;\n\n if (!toastRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n toastRoots.set(targetContainer, root);\n root.render(<ToastStackRenderer 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\nToast.destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n toastRoots.forEach((root, container) => {\n root.unmount();\n toastRootElements.get(container)?.remove();\n toastRootElements.delete(container);\n });\n toastRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(toast => toast.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(toast => toast.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n toastRoots.get(container)?.unmount();\n toastRoots.delete(container);\n containerStates.delete(container);\n toastRootElements.get(container)?.remove();\n toastRootElements.delete(container);\n }\n });\n};\n\nToast.destroyAll = () => {\n Toast.destroy();\n};\n\ntype TriggerOptions = Omit<StaticProps, 'type' | 'title'>;\n\nToast.info = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'info', title, ...props });\nToast.success = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'success', title, ...props });\nToast.error = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'error', title, ...props });\nToast.warning = (title: React.ReactNode, props?: TriggerOptions) =>\n renderToast({ type: 'warning', title, ...props });\n\nexport default Toast;\nexport type { StaticProps as ToastOptions };\n"],"mappings":"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"}
|
package/dist/core/badge.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ declare namespace badge_d_exports {
|
|
|
8
8
|
export { Badge, Props, badgeVariants };
|
|
9
9
|
}
|
|
10
10
|
declare const badgeVariants: (props?: ({
|
|
11
|
-
variant?: "default" | "
|
|
11
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
13
13
|
type Props = React$1.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & {
|
|
14
14
|
asChild?: boolean;
|
package/dist/core/button.d.mts
CHANGED
|
@@ -8,8 +8,8 @@ declare namespace button_d_exports {
|
|
|
8
8
|
export { Button, Props, buttonVariants };
|
|
9
9
|
}
|
|
10
10
|
declare const buttonVariants: (props?: ({
|
|
11
|
-
variant?: "link" | "default" | "
|
|
12
|
-
size?: "
|
|
11
|
+
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
12
|
+
size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
14
14
|
type Props = React$1.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
|
15
15
|
asChild?: boolean;
|
package/dist/style.css
CHANGED
|
@@ -275,15 +275,27 @@
|
|
|
275
275
|
.right-5 {
|
|
276
276
|
right: calc(var(--spacing) * 5);
|
|
277
277
|
}
|
|
278
|
+
.right-full {
|
|
279
|
+
right: 100%;
|
|
280
|
+
}
|
|
281
|
+
.bottom-4 {
|
|
282
|
+
bottom: calc(var(--spacing) * 4);
|
|
283
|
+
}
|
|
278
284
|
.bottom-5 {
|
|
279
285
|
bottom: calc(var(--spacing) * 5);
|
|
280
286
|
}
|
|
287
|
+
.bottom-full {
|
|
288
|
+
bottom: 100%;
|
|
289
|
+
}
|
|
281
290
|
.left-0 {
|
|
282
291
|
left: calc(var(--spacing) * 0);
|
|
283
292
|
}
|
|
284
293
|
.left-1\/2 {
|
|
285
294
|
left: calc(1/2 * 100%);
|
|
286
295
|
}
|
|
296
|
+
.left-4 {
|
|
297
|
+
left: calc(var(--spacing) * 4);
|
|
298
|
+
}
|
|
287
299
|
.left-\[50\%\] {
|
|
288
300
|
left: 50%;
|
|
289
301
|
}
|
|
@@ -422,6 +434,9 @@
|
|
|
422
434
|
.inline-flex {
|
|
423
435
|
display: inline-flex;
|
|
424
436
|
}
|
|
437
|
+
.table {
|
|
438
|
+
display: table;
|
|
439
|
+
}
|
|
425
440
|
.field-sizing-content {
|
|
426
441
|
field-sizing: content;
|
|
427
442
|
}
|
|
@@ -885,6 +900,10 @@
|
|
|
885
900
|
border-top-left-radius: var(--radius);
|
|
886
901
|
border-top-right-radius: var(--radius);
|
|
887
902
|
}
|
|
903
|
+
.rounded-l-\[30px\]\! {
|
|
904
|
+
border-top-left-radius: 30px !important;
|
|
905
|
+
border-bottom-left-radius: 30px !important;
|
|
906
|
+
}
|
|
888
907
|
.rounded-l-lg {
|
|
889
908
|
border-top-left-radius: var(--radius);
|
|
890
909
|
border-bottom-left-radius: var(--radius);
|
|
@@ -897,6 +916,10 @@
|
|
|
897
916
|
border-top-left-radius: 0;
|
|
898
917
|
border-bottom-left-radius: 0;
|
|
899
918
|
}
|
|
919
|
+
.rounded-r-\[30px\]\! {
|
|
920
|
+
border-top-right-radius: 30px !important;
|
|
921
|
+
border-bottom-right-radius: 30px !important;
|
|
922
|
+
}
|
|
900
923
|
.rounded-r-lg {
|
|
901
924
|
border-top-right-radius: var(--radius);
|
|
902
925
|
border-bottom-right-radius: var(--radius);
|
|
@@ -909,6 +932,10 @@
|
|
|
909
932
|
border-top-right-radius: 0;
|
|
910
933
|
border-bottom-right-radius: 0;
|
|
911
934
|
}
|
|
935
|
+
.rounded-b-\[30px\]\! {
|
|
936
|
+
border-bottom-right-radius: 30px !important;
|
|
937
|
+
border-bottom-left-radius: 30px !important;
|
|
938
|
+
}
|
|
912
939
|
.rounded-b-lg {
|
|
913
940
|
border-bottom-right-radius: var(--radius);
|
|
914
941
|
border-bottom-left-radius: var(--radius);
|
|
@@ -1617,6 +1644,42 @@
|
|
|
1617
1644
|
position: absolute;
|
|
1618
1645
|
}
|
|
1619
1646
|
}
|
|
1647
|
+
.before\:top-0 {
|
|
1648
|
+
&::before {
|
|
1649
|
+
content: var(--tw-content);
|
|
1650
|
+
top: calc(var(--spacing) * 0);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
.before\:top-1\/2 {
|
|
1654
|
+
&::before {
|
|
1655
|
+
content: var(--tw-content);
|
|
1656
|
+
top: calc(1/2 * 100%);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
.before\:right-0 {
|
|
1660
|
+
&::before {
|
|
1661
|
+
content: var(--tw-content);
|
|
1662
|
+
right: calc(var(--spacing) * 0);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
.before\:bottom-0 {
|
|
1666
|
+
&::before {
|
|
1667
|
+
content: var(--tw-content);
|
|
1668
|
+
bottom: calc(var(--spacing) * 0);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
.before\:left-0 {
|
|
1672
|
+
&::before {
|
|
1673
|
+
content: var(--tw-content);
|
|
1674
|
+
left: calc(var(--spacing) * 0);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
.before\:left-1\/2 {
|
|
1678
|
+
&::before {
|
|
1679
|
+
content: var(--tw-content);
|
|
1680
|
+
left: calc(1/2 * 100%);
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1620
1683
|
.before\:h-0 {
|
|
1621
1684
|
&::before {
|
|
1622
1685
|
content: var(--tw-content);
|
|
@@ -1629,6 +1692,20 @@
|
|
|
1629
1692
|
width: calc(var(--spacing) * 0);
|
|
1630
1693
|
}
|
|
1631
1694
|
}
|
|
1695
|
+
.before\:-translate-x-1\/2 {
|
|
1696
|
+
&::before {
|
|
1697
|
+
content: var(--tw-content);
|
|
1698
|
+
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
|
1699
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
.before\:-translate-y-1\/2 {
|
|
1703
|
+
&::before {
|
|
1704
|
+
content: var(--tw-content);
|
|
1705
|
+
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
|
1706
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1632
1709
|
.before\:border-t-\[9px\] {
|
|
1633
1710
|
&::before {
|
|
1634
1711
|
content: var(--tw-content);
|
|
@@ -1723,12 +1800,66 @@
|
|
|
1723
1800
|
inset-block: calc(var(--spacing) * 0);
|
|
1724
1801
|
}
|
|
1725
1802
|
}
|
|
1803
|
+
.after\:-top-px {
|
|
1804
|
+
&::after {
|
|
1805
|
+
content: var(--tw-content);
|
|
1806
|
+
top: -1px;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
.after\:top-1\/2 {
|
|
1810
|
+
&::after {
|
|
1811
|
+
content: var(--tw-content);
|
|
1812
|
+
top: calc(1/2 * 100%);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
.after\:top-px {
|
|
1816
|
+
&::after {
|
|
1817
|
+
content: var(--tw-content);
|
|
1818
|
+
top: 1px;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
.after\:-right-px {
|
|
1822
|
+
&::after {
|
|
1823
|
+
content: var(--tw-content);
|
|
1824
|
+
right: -1px;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
.after\:right-px {
|
|
1828
|
+
&::after {
|
|
1829
|
+
content: var(--tw-content);
|
|
1830
|
+
right: 1px;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
.after\:-bottom-px {
|
|
1834
|
+
&::after {
|
|
1835
|
+
content: var(--tw-content);
|
|
1836
|
+
bottom: -1px;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
.after\:bottom-px {
|
|
1840
|
+
&::after {
|
|
1841
|
+
content: var(--tw-content);
|
|
1842
|
+
bottom: 1px;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
.after\:-left-px {
|
|
1846
|
+
&::after {
|
|
1847
|
+
content: var(--tw-content);
|
|
1848
|
+
left: -1px;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1726
1851
|
.after\:left-1\/2 {
|
|
1727
1852
|
&::after {
|
|
1728
1853
|
content: var(--tw-content);
|
|
1729
1854
|
left: calc(1/2 * 100%);
|
|
1730
1855
|
}
|
|
1731
1856
|
}
|
|
1857
|
+
.after\:left-px {
|
|
1858
|
+
&::after {
|
|
1859
|
+
content: var(--tw-content);
|
|
1860
|
+
left: 1px;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1732
1863
|
.after\:h-0 {
|
|
1733
1864
|
&::after {
|
|
1734
1865
|
content: var(--tw-content);
|
|
@@ -1754,6 +1885,13 @@
|
|
|
1754
1885
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1755
1886
|
}
|
|
1756
1887
|
}
|
|
1888
|
+
.after\:-translate-y-1\/2 {
|
|
1889
|
+
&::after {
|
|
1890
|
+
content: var(--tw-content);
|
|
1891
|
+
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
|
1892
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1757
1895
|
.after\:border-t-8 {
|
|
1758
1896
|
&::after {
|
|
1759
1897
|
content: var(--tw-content);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbpark/ui-kit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Modern React UI component library built with TypeScript, Tailwind CSS, and Radix UI. Featuring atoms, molecules, organisms and layout templates for building beautiful interfaces.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|