@wheeparam/library 0.0.1

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.
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/react/index.ts
31
+ var react_exports = {};
32
+ __export(react_exports, {
33
+ nl2br: () => nl2br,
34
+ useFormLayer: () => useFormLayer,
35
+ useSortLayer: () => useSortLayer
36
+ });
37
+ module.exports = __toCommonJS(react_exports);
38
+
39
+ // src/react/useFormLayer.ts
40
+ var import_react = require("react");
41
+ function useFormLayer() {
42
+ const [opened, setOpened] = (0, import_react.useState)(false);
43
+ const [mode, setMode] = (0, import_react.useState)(null);
44
+ const [id, setId] = (0, import_react.useState)(null);
45
+ const [parentId, setParentId] = (0, import_react.useState)(null);
46
+ const [payload, setPayload] = (0, import_react.useState)(null);
47
+ const open = (0, import_react.useCallback)(
48
+ (args) => {
49
+ setMode(args.mode);
50
+ setId(args.id ?? null);
51
+ setParentId(args.parentId ?? null);
52
+ setPayload(args.payload ?? null);
53
+ setOpened(true);
54
+ },
55
+ []
56
+ );
57
+ const openCreate = (0, import_react.useCallback)((pId, pl) => {
58
+ open({ mode: "create", parentId: pId ?? null, id: null, payload: pl ?? null });
59
+ }, [open]);
60
+ const openEdit = (0, import_react.useCallback)((editId, pId, pl) => {
61
+ open({ mode: "edit", id: editId, parentId: pId ?? null, payload: pl ?? null });
62
+ }, [open]);
63
+ const close = (0, import_react.useCallback)(() => {
64
+ setOpened(false);
65
+ setMode(null);
66
+ setId(null);
67
+ setParentId(null);
68
+ setPayload(null);
69
+ }, []);
70
+ return {
71
+ opened,
72
+ mode,
73
+ id,
74
+ parentId,
75
+ payload,
76
+ open,
77
+ openCreate,
78
+ openEdit,
79
+ close,
80
+ setOpened,
81
+ setId,
82
+ setParentId,
83
+ setMode,
84
+ setPayload
85
+ };
86
+ }
87
+
88
+ // src/react/useSortLayer.ts
89
+ var import_react2 = require("react");
90
+ function useSortLayer(props) {
91
+ const { list, setList, onSave, clone } = props;
92
+ const [enabled, setEnabled] = (0, import_react2.useState)(false);
93
+ const backupRef = (0, import_react2.useRef)(null);
94
+ const cloneFn = (0, import_react2.useMemo)(() => {
95
+ return clone ?? ((items) => items.slice());
96
+ }, [clone]);
97
+ const start = (0, import_react2.useCallback)(() => {
98
+ backupRef.current = cloneFn(list);
99
+ setEnabled(true);
100
+ }, [cloneFn, list]);
101
+ const cancel = (0, import_react2.useCallback)(() => {
102
+ if (backupRef.current) {
103
+ setList(backupRef.current);
104
+ }
105
+ backupRef.current = null;
106
+ setEnabled(false);
107
+ }, [setList]);
108
+ const save = (0, import_react2.useCallback)(() => {
109
+ setEnabled(false);
110
+ backupRef.current = null;
111
+ onSave?.(cloneFn(list));
112
+ }, [cloneFn, list, onSave]);
113
+ return { start, cancel, save, enabled };
114
+ }
115
+
116
+ // src/react/nl2br.tsx
117
+ var import_jsx_runtime = __toESM(require("react/jsx-runtime"), 1);
118
+ function nl2br(text) {
119
+ const newlineRegex = /(\r\n|\r|\n)/g;
120
+ if (!text) return "";
121
+ const props = {};
122
+ return text.split(newlineRegex).map(function(line, index) {
123
+ if (line.match(newlineRegex)) {
124
+ return import_jsx_runtime.default.jsx("br", { key: index, ...props });
125
+ }
126
+ return line;
127
+ });
128
+ }
129
+ // Annotate the CommonJS export names for ESM import in node:
130
+ 0 && (module.exports = {
131
+ nl2br,
132
+ useFormLayer,
133
+ useSortLayer
134
+ });
@@ -0,0 +1,178 @@
1
+ import * as react from 'react';
2
+ import { Dispatch, SetStateAction } from 'react';
3
+
4
+ /**
5
+ * @packageDocumentation
6
+ * ๋ชจ๋‹ฌ/๋ ˆ์ด์–ด ์ƒํƒœ(์—ด๋ฆผ ์—ฌ๋ถ€ + ์ปจํ…์ŠคํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ)๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React Hook
7
+ */
8
+ /**
9
+ * ๋ ˆ์ด์–ด(๋ชจ๋‹ฌ)์˜ ๋™์ž‘ ๋ชจ๋“œ
10
+ * - create: ์ƒ์„ฑ ๋ชจ๋“œ
11
+ * - edit: ์ˆ˜์ • ๋ชจ๋“œ
12
+ */
13
+ type FormLayerMode = "create" | "edit";
14
+ /**
15
+ * useFormLayer๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ œ์–ด ๊ฐ์ฒด ํƒ€์ž…
16
+ *
17
+ * @template T id/parentId์˜ ํƒ€์ž… (string | number)
18
+ * @template P payload ํƒ€์ž… (์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ)
19
+ */
20
+ type UseFormLayerReturn<T extends string | number, P> = {
21
+ /** ๋ชจ๋‹ฌ ์—ด๋ฆผ ์—ฌ๋ถ€ */
22
+ opened: boolean;
23
+ /** ํ˜„์žฌ ๋ชจ๋‹ฌ ๋ชจ๋“œ(create/edit). ๋‹ซํ˜€์žˆ์œผ๋ฉด null */
24
+ mode: FormLayerMode | null;
25
+ /** edit ๋ชจ๋“œ์—์„œ ์ฃผ๋กœ ์“ฐ๋Š” PK. create ๋ชจ๋“œ์ผ ๋•Œ๋Š” ๋ณดํ†ต null */
26
+ id: T | null;
27
+ /** ๋ถ€๋ชจ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ (์˜ˆ: ํŠธ๋ฆฌ์—์„œ ํŠน์ • ๋…ธ๋“œ ์•„๋ž˜ ์ƒ์„ฑ) */
28
+ parentId: T | null;
29
+ /** ๋ชจ๋‹ฌ์„ ์—ด ๋•Œ ํ•จ๊ป˜ ๋„˜๊ธฐ๊ณ  ์‹ถ์€ ์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ (์„ ํƒ) */
30
+ payload: P | null;
31
+ /**
32
+ * ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(์ผ๋ฐ˜ํ˜•)
33
+ * @example
34
+ * layer.open({ mode: "edit", id: 10 })
35
+ * layer.open({ mode: "create", parentId: 5 })
36
+ */
37
+ open: (args: {
38
+ mode: FormLayerMode;
39
+ id?: T | null;
40
+ parentId?: T | null;
41
+ payload?: P | null;
42
+ }) => void;
43
+ /** ๋ชจ๋‹ฌ์„ ๋‹ซ๊ณ  ๋‚ด๋ถ€ ์ƒํƒœ(id/parentId/payload ๋“ฑ)๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค */
44
+ close: () => void;
45
+ /**
46
+ * ์ƒ์„ฑ ๋ชจ๋“œ๋กœ ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(๋‹จ์ถ•ํ˜•)
47
+ * @example
48
+ * layer.openCreate()
49
+ * layer.openCreate(3) // parentId=3 ์•„๋ž˜ ์ƒ์„ฑ
50
+ */
51
+ openCreate: (parentId?: T | null, payload?: P | null) => void;
52
+ /**
53
+ * ์ˆ˜์ • ๋ชจ๋“œ๋กœ ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(๋‹จ์ถ•ํ˜•)
54
+ * @example
55
+ * layer.openEdit(10)
56
+ * layer.openEdit(10, 3) // id=10 ํŽธ์ง‘, parentId=3 ์ปจํ…์ŠคํŠธ
57
+ */
58
+ openEdit: (id: T, parentId?: T | null, payload?: P | null) => void;
59
+ /** ํ•„์š” ์‹œ ์ˆ˜๋™ ์ œ์–ด๋ฅผ ์œ„ํ•œ raw setter๋“ค */
60
+ setOpened: React.Dispatch<React.SetStateAction<boolean>>;
61
+ setId: React.Dispatch<React.SetStateAction<T | null>>;
62
+ setParentId: React.Dispatch<React.SetStateAction<T | null>>;
63
+ setMode: React.Dispatch<React.SetStateAction<FormLayerMode | null>>;
64
+ setPayload: React.Dispatch<React.SetStateAction<P | null>>;
65
+ };
66
+ /**
67
+ * ๋ชจ๋‹ฌ/๋ ˆ์ด์–ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React ํ›…
68
+ *
69
+ * โ€œ๋ชจ๋‹ฌ open state + ์ „๋‹ฌ ํŒŒ๋ผ๋ฏธํ„ฐ stateโ€๋ฅผ ๋งค๋ฒˆ ๋งŒ๋“ค๊ธฐ ๊ท€์ฐฎ์„ ๋•Œ ์“ฐ๋Š” ๋ชฉ์ ์— ์ตœ์ ํ™”๋˜์–ด ์žˆ๋‹ค.
70
+ * create/edit ๋ชจ๋“œ, id/parentId, payload(์„ ํƒ)๋ฅผ ํ•œ ๋ฒˆ์— ๊ด€๋ฆฌํ•œ๋‹ค.
71
+ *
72
+ * @returns ๋ ˆ์ด์–ด ์ œ์–ด ๊ฐ์ฒด
73
+ *
74
+ * @example
75
+ * const layer = useFormLayer<number>()
76
+ * layer.openCreate()
77
+ * layer.openEdit(10)
78
+ */
79
+ declare function useFormLayer<T extends string | number = string, P = never>(): UseFormLayerReturn<T, P>;
80
+
81
+ /**
82
+ * @packageDocumentation
83
+ * ๋ชฉ๋ก์˜ โ€œ์ •๋ ฌ ๋ชจ๋“œโ€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React Hook
84
+ *
85
+ * - start(): ํ˜„์žฌ list๋ฅผ ๋ฐฑ์—…ํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ(enabled=true)๋กœ ์ง„์ž…
86
+ * - cancel(): ๋ฐฑ์—…๋ณธ์œผ๋กœ list๋ฅผ ๋ณต๊ตฌํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ ์ข…๋ฃŒ
87
+ * - save(): ์ •๋ ฌ๋ชจ๋“œ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  onSave(list)๋ฅผ ํ˜ธ์ถœ
88
+ */
89
+
90
+ /**
91
+ * useSortLayer ์ž…๋ ฅ Props
92
+ *
93
+ * @template T ๋ชฉ๋ก ์•„์ดํ…œ ํƒ€์ž…
94
+ */
95
+ type UseSortLayerProps<T> = {
96
+ /** ํ˜„์žฌ ๋ชฉ๋ก */
97
+ list: T[];
98
+ /** ๋ชฉ๋ก setter */
99
+ setList: Dispatch<SetStateAction<T[]>>;
100
+ /** ์ €์žฅ ์ฝœ๋ฐฑ(์„ ํƒ) */
101
+ onSave?: (items: T[]) => void;
102
+ /**
103
+ * ์Šค๋ƒ…์ƒท ๋ณต์‚ฌ ๋ฐฉ์‹ (๊ธฐ๋ณธ shallow)
104
+ * - shallow: [...list]
105
+ * - deep: structuredClone(list) (๋ธŒ๋ผ์šฐ์ € ์ง€์› ํ•„์š”)
106
+ * - custom: (items) => ...
107
+ */
108
+ clone?: (items: T[]) => T[];
109
+ };
110
+ /**
111
+ * useSortLayer ๋ฐ˜ํ™˜ ํƒ€์ž…
112
+ */
113
+ type UseSortLayerReturn = {
114
+ /** ์ •๋ ฌ๋ชจ๋“œ ์‹œ์ž‘ (ํ˜„์žฌ list ์Šค๋ƒ…์ƒท ๋ฐฑ์—…) */
115
+ start: () => void;
116
+ /** ์ •๋ ฌ๋ชจ๋“œ ์ทจ์†Œ (๋ฐฑ์—…๋ณธ์œผ๋กœ ๋ณต๊ตฌ) */
117
+ cancel: () => void;
118
+ /** ์ •๋ ฌ๋ชจ๋“œ ์ €์žฅ(์ข…๋ฃŒ) */
119
+ save: () => void;
120
+ /** ์ •๋ ฌ๋ชจ๋“œ ์—ฌ๋ถ€ */
121
+ enabled: boolean;
122
+ };
123
+ /**
124
+ * ๋ชฉ๋ก ์ •๋ ฌ ๋ชจ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ›…
125
+ *
126
+ * start() ํ˜ธ์ถœ ์‹œ ํ˜„์žฌ ๋ชฉ๋ก์„ ๋ฐฑ์—…ํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ๋กœ ์ง„์ž…ํ•œ๋‹ค.
127
+ * cancel() ํ˜ธ์ถœ ์‹œ ์›๋ž˜ ์ƒํƒœ๋กœ ๋ณต๊ตฌ๋œ๋‹ค.
128
+ * save() ํ˜ธ์ถœ ์‹œ onSave๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
129
+ *
130
+ * @example
131
+ * const sort = useSortLayer({ list, setList, onSave })
132
+ * sort.start()
133
+ * // ... drag & drop ๋“ฑ์œผ๋กœ list ์ˆœ์„œ ๋ณ€๊ฒฝ ...
134
+ * sort.cancel()
135
+ * // ๋˜๋Š”
136
+ * sort.save()
137
+ */
138
+ declare function useSortLayer<T>(props: UseSortLayerProps<T>): UseSortLayerReturn;
139
+
140
+ /**
141
+ * ๋ฌธ์ž์—ด์˜ ์ค„๋ฐ”๊ฟˆ(\n)์„ `<br />` ์š”์†Œ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
142
+ *
143
+ * ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ / ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋‘์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
144
+ *
145
+ * @param text ์ค„๋ฐ”๊ฟˆ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž์—ด
146
+ * @returns ReactNode ๋ฐฐ์—ด (๋ฌธ์ž์—ด + `<br />`)
147
+ *
148
+ * @example ๊ธฐ๋ณธ ์‚ฌ์šฉ
149
+ * ```tsx
150
+ * import { nl2br } from "@your-scope/toolkit/react";
151
+ *
152
+ * export default function Page() {
153
+ * return (
154
+ * <div>
155
+ * {nl2br("์ฒซ์ค„\n๋‘˜์งธ์ค„\n์…‹์งธ์ค„")}
156
+ * </div>
157
+ * );
158
+ * }
159
+ * ```
160
+ *
161
+ * @example API ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
162
+ * ```tsx
163
+ * Swal.fire({
164
+ * title: "์˜ค๋ฅ˜ ๋ฐœ์ƒ",
165
+ * html: nl2br(message),
166
+ * });
167
+ * ```
168
+ *
169
+ * @example textarea ๋ฏธ๋ฆฌ๋ณด๊ธฐ
170
+ * ```tsx
171
+ * <div className="preview">
172
+ * {nl2br(form.content)}
173
+ * </div>
174
+ * ```
175
+ */
176
+ declare function nl2br(text: string | null | undefined): "" | (string | react.ReactElement<unknown, string | react.JSXElementConstructor<any>>)[];
177
+
178
+ export { type FormLayerMode, type UseFormLayerReturn, type UseSortLayerProps, type UseSortLayerReturn, nl2br, useFormLayer, useSortLayer };
@@ -0,0 +1,178 @@
1
+ import * as react from 'react';
2
+ import { Dispatch, SetStateAction } from 'react';
3
+
4
+ /**
5
+ * @packageDocumentation
6
+ * ๋ชจ๋‹ฌ/๋ ˆ์ด์–ด ์ƒํƒœ(์—ด๋ฆผ ์—ฌ๋ถ€ + ์ปจํ…์ŠคํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ)๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React Hook
7
+ */
8
+ /**
9
+ * ๋ ˆ์ด์–ด(๋ชจ๋‹ฌ)์˜ ๋™์ž‘ ๋ชจ๋“œ
10
+ * - create: ์ƒ์„ฑ ๋ชจ๋“œ
11
+ * - edit: ์ˆ˜์ • ๋ชจ๋“œ
12
+ */
13
+ type FormLayerMode = "create" | "edit";
14
+ /**
15
+ * useFormLayer๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ œ์–ด ๊ฐ์ฒด ํƒ€์ž…
16
+ *
17
+ * @template T id/parentId์˜ ํƒ€์ž… (string | number)
18
+ * @template P payload ํƒ€์ž… (์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ)
19
+ */
20
+ type UseFormLayerReturn<T extends string | number, P> = {
21
+ /** ๋ชจ๋‹ฌ ์—ด๋ฆผ ์—ฌ๋ถ€ */
22
+ opened: boolean;
23
+ /** ํ˜„์žฌ ๋ชจ๋‹ฌ ๋ชจ๋“œ(create/edit). ๋‹ซํ˜€์žˆ์œผ๋ฉด null */
24
+ mode: FormLayerMode | null;
25
+ /** edit ๋ชจ๋“œ์—์„œ ์ฃผ๋กœ ์“ฐ๋Š” PK. create ๋ชจ๋“œ์ผ ๋•Œ๋Š” ๋ณดํ†ต null */
26
+ id: T | null;
27
+ /** ๋ถ€๋ชจ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ (์˜ˆ: ํŠธ๋ฆฌ์—์„œ ํŠน์ • ๋…ธ๋“œ ์•„๋ž˜ ์ƒ์„ฑ) */
28
+ parentId: T | null;
29
+ /** ๋ชจ๋‹ฌ์„ ์—ด ๋•Œ ํ•จ๊ป˜ ๋„˜๊ธฐ๊ณ  ์‹ถ์€ ์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ (์„ ํƒ) */
30
+ payload: P | null;
31
+ /**
32
+ * ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(์ผ๋ฐ˜ํ˜•)
33
+ * @example
34
+ * layer.open({ mode: "edit", id: 10 })
35
+ * layer.open({ mode: "create", parentId: 5 })
36
+ */
37
+ open: (args: {
38
+ mode: FormLayerMode;
39
+ id?: T | null;
40
+ parentId?: T | null;
41
+ payload?: P | null;
42
+ }) => void;
43
+ /** ๋ชจ๋‹ฌ์„ ๋‹ซ๊ณ  ๋‚ด๋ถ€ ์ƒํƒœ(id/parentId/payload ๋“ฑ)๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค */
44
+ close: () => void;
45
+ /**
46
+ * ์ƒ์„ฑ ๋ชจ๋“œ๋กœ ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(๋‹จ์ถ•ํ˜•)
47
+ * @example
48
+ * layer.openCreate()
49
+ * layer.openCreate(3) // parentId=3 ์•„๋ž˜ ์ƒ์„ฑ
50
+ */
51
+ openCreate: (parentId?: T | null, payload?: P | null) => void;
52
+ /**
53
+ * ์ˆ˜์ • ๋ชจ๋“œ๋กœ ๋ชจ๋‹ฌ์„ ์—ฐ๋‹ค(๋‹จ์ถ•ํ˜•)
54
+ * @example
55
+ * layer.openEdit(10)
56
+ * layer.openEdit(10, 3) // id=10 ํŽธ์ง‘, parentId=3 ์ปจํ…์ŠคํŠธ
57
+ */
58
+ openEdit: (id: T, parentId?: T | null, payload?: P | null) => void;
59
+ /** ํ•„์š” ์‹œ ์ˆ˜๋™ ์ œ์–ด๋ฅผ ์œ„ํ•œ raw setter๋“ค */
60
+ setOpened: React.Dispatch<React.SetStateAction<boolean>>;
61
+ setId: React.Dispatch<React.SetStateAction<T | null>>;
62
+ setParentId: React.Dispatch<React.SetStateAction<T | null>>;
63
+ setMode: React.Dispatch<React.SetStateAction<FormLayerMode | null>>;
64
+ setPayload: React.Dispatch<React.SetStateAction<P | null>>;
65
+ };
66
+ /**
67
+ * ๋ชจ๋‹ฌ/๋ ˆ์ด์–ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React ํ›…
68
+ *
69
+ * โ€œ๋ชจ๋‹ฌ open state + ์ „๋‹ฌ ํŒŒ๋ผ๋ฏธํ„ฐ stateโ€๋ฅผ ๋งค๋ฒˆ ๋งŒ๋“ค๊ธฐ ๊ท€์ฐฎ์„ ๋•Œ ์“ฐ๋Š” ๋ชฉ์ ์— ์ตœ์ ํ™”๋˜์–ด ์žˆ๋‹ค.
70
+ * create/edit ๋ชจ๋“œ, id/parentId, payload(์„ ํƒ)๋ฅผ ํ•œ ๋ฒˆ์— ๊ด€๋ฆฌํ•œ๋‹ค.
71
+ *
72
+ * @returns ๋ ˆ์ด์–ด ์ œ์–ด ๊ฐ์ฒด
73
+ *
74
+ * @example
75
+ * const layer = useFormLayer<number>()
76
+ * layer.openCreate()
77
+ * layer.openEdit(10)
78
+ */
79
+ declare function useFormLayer<T extends string | number = string, P = never>(): UseFormLayerReturn<T, P>;
80
+
81
+ /**
82
+ * @packageDocumentation
83
+ * ๋ชฉ๋ก์˜ โ€œ์ •๋ ฌ ๋ชจ๋“œโ€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React Hook
84
+ *
85
+ * - start(): ํ˜„์žฌ list๋ฅผ ๋ฐฑ์—…ํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ(enabled=true)๋กœ ์ง„์ž…
86
+ * - cancel(): ๋ฐฑ์—…๋ณธ์œผ๋กœ list๋ฅผ ๋ณต๊ตฌํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ ์ข…๋ฃŒ
87
+ * - save(): ์ •๋ ฌ๋ชจ๋“œ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  onSave(list)๋ฅผ ํ˜ธ์ถœ
88
+ */
89
+
90
+ /**
91
+ * useSortLayer ์ž…๋ ฅ Props
92
+ *
93
+ * @template T ๋ชฉ๋ก ์•„์ดํ…œ ํƒ€์ž…
94
+ */
95
+ type UseSortLayerProps<T> = {
96
+ /** ํ˜„์žฌ ๋ชฉ๋ก */
97
+ list: T[];
98
+ /** ๋ชฉ๋ก setter */
99
+ setList: Dispatch<SetStateAction<T[]>>;
100
+ /** ์ €์žฅ ์ฝœ๋ฐฑ(์„ ํƒ) */
101
+ onSave?: (items: T[]) => void;
102
+ /**
103
+ * ์Šค๋ƒ…์ƒท ๋ณต์‚ฌ ๋ฐฉ์‹ (๊ธฐ๋ณธ shallow)
104
+ * - shallow: [...list]
105
+ * - deep: structuredClone(list) (๋ธŒ๋ผ์šฐ์ € ์ง€์› ํ•„์š”)
106
+ * - custom: (items) => ...
107
+ */
108
+ clone?: (items: T[]) => T[];
109
+ };
110
+ /**
111
+ * useSortLayer ๋ฐ˜ํ™˜ ํƒ€์ž…
112
+ */
113
+ type UseSortLayerReturn = {
114
+ /** ์ •๋ ฌ๋ชจ๋“œ ์‹œ์ž‘ (ํ˜„์žฌ list ์Šค๋ƒ…์ƒท ๋ฐฑ์—…) */
115
+ start: () => void;
116
+ /** ์ •๋ ฌ๋ชจ๋“œ ์ทจ์†Œ (๋ฐฑ์—…๋ณธ์œผ๋กœ ๋ณต๊ตฌ) */
117
+ cancel: () => void;
118
+ /** ์ •๋ ฌ๋ชจ๋“œ ์ €์žฅ(์ข…๋ฃŒ) */
119
+ save: () => void;
120
+ /** ์ •๋ ฌ๋ชจ๋“œ ์—ฌ๋ถ€ */
121
+ enabled: boolean;
122
+ };
123
+ /**
124
+ * ๋ชฉ๋ก ์ •๋ ฌ ๋ชจ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ›…
125
+ *
126
+ * start() ํ˜ธ์ถœ ์‹œ ํ˜„์žฌ ๋ชฉ๋ก์„ ๋ฐฑ์—…ํ•˜๊ณ  ์ •๋ ฌ๋ชจ๋“œ๋กœ ์ง„์ž…ํ•œ๋‹ค.
127
+ * cancel() ํ˜ธ์ถœ ์‹œ ์›๋ž˜ ์ƒํƒœ๋กœ ๋ณต๊ตฌ๋œ๋‹ค.
128
+ * save() ํ˜ธ์ถœ ์‹œ onSave๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
129
+ *
130
+ * @example
131
+ * const sort = useSortLayer({ list, setList, onSave })
132
+ * sort.start()
133
+ * // ... drag & drop ๋“ฑ์œผ๋กœ list ์ˆœ์„œ ๋ณ€๊ฒฝ ...
134
+ * sort.cancel()
135
+ * // ๋˜๋Š”
136
+ * sort.save()
137
+ */
138
+ declare function useSortLayer<T>(props: UseSortLayerProps<T>): UseSortLayerReturn;
139
+
140
+ /**
141
+ * ๋ฌธ์ž์—ด์˜ ์ค„๋ฐ”๊ฟˆ(\n)์„ `<br />` ์š”์†Œ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
142
+ *
143
+ * ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ / ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋‘์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
144
+ *
145
+ * @param text ์ค„๋ฐ”๊ฟˆ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž์—ด
146
+ * @returns ReactNode ๋ฐฐ์—ด (๋ฌธ์ž์—ด + `<br />`)
147
+ *
148
+ * @example ๊ธฐ๋ณธ ์‚ฌ์šฉ
149
+ * ```tsx
150
+ * import { nl2br } from "@your-scope/toolkit/react";
151
+ *
152
+ * export default function Page() {
153
+ * return (
154
+ * <div>
155
+ * {nl2br("์ฒซ์ค„\n๋‘˜์งธ์ค„\n์…‹์งธ์ค„")}
156
+ * </div>
157
+ * );
158
+ * }
159
+ * ```
160
+ *
161
+ * @example API ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
162
+ * ```tsx
163
+ * Swal.fire({
164
+ * title: "์˜ค๋ฅ˜ ๋ฐœ์ƒ",
165
+ * html: nl2br(message),
166
+ * });
167
+ * ```
168
+ *
169
+ * @example textarea ๋ฏธ๋ฆฌ๋ณด๊ธฐ
170
+ * ```tsx
171
+ * <div className="preview">
172
+ * {nl2br(form.content)}
173
+ * </div>
174
+ * ```
175
+ */
176
+ declare function nl2br(text: string | null | undefined): "" | (string | react.ReactElement<unknown, string | react.JSXElementConstructor<any>>)[];
177
+
178
+ export { type FormLayerMode, type UseFormLayerReturn, type UseSortLayerProps, type UseSortLayerReturn, nl2br, useFormLayer, useSortLayer };
@@ -0,0 +1,95 @@
1
+ // src/react/useFormLayer.ts
2
+ import { useCallback, useState } from "react";
3
+ function useFormLayer() {
4
+ const [opened, setOpened] = useState(false);
5
+ const [mode, setMode] = useState(null);
6
+ const [id, setId] = useState(null);
7
+ const [parentId, setParentId] = useState(null);
8
+ const [payload, setPayload] = useState(null);
9
+ const open = useCallback(
10
+ (args) => {
11
+ setMode(args.mode);
12
+ setId(args.id ?? null);
13
+ setParentId(args.parentId ?? null);
14
+ setPayload(args.payload ?? null);
15
+ setOpened(true);
16
+ },
17
+ []
18
+ );
19
+ const openCreate = useCallback((pId, pl) => {
20
+ open({ mode: "create", parentId: pId ?? null, id: null, payload: pl ?? null });
21
+ }, [open]);
22
+ const openEdit = useCallback((editId, pId, pl) => {
23
+ open({ mode: "edit", id: editId, parentId: pId ?? null, payload: pl ?? null });
24
+ }, [open]);
25
+ const close = useCallback(() => {
26
+ setOpened(false);
27
+ setMode(null);
28
+ setId(null);
29
+ setParentId(null);
30
+ setPayload(null);
31
+ }, []);
32
+ return {
33
+ opened,
34
+ mode,
35
+ id,
36
+ parentId,
37
+ payload,
38
+ open,
39
+ openCreate,
40
+ openEdit,
41
+ close,
42
+ setOpened,
43
+ setId,
44
+ setParentId,
45
+ setMode,
46
+ setPayload
47
+ };
48
+ }
49
+
50
+ // src/react/useSortLayer.ts
51
+ import { useCallback as useCallback2, useMemo, useRef, useState as useState2 } from "react";
52
+ function useSortLayer(props) {
53
+ const { list, setList, onSave, clone } = props;
54
+ const [enabled, setEnabled] = useState2(false);
55
+ const backupRef = useRef(null);
56
+ const cloneFn = useMemo(() => {
57
+ return clone ?? ((items) => items.slice());
58
+ }, [clone]);
59
+ const start = useCallback2(() => {
60
+ backupRef.current = cloneFn(list);
61
+ setEnabled(true);
62
+ }, [cloneFn, list]);
63
+ const cancel = useCallback2(() => {
64
+ if (backupRef.current) {
65
+ setList(backupRef.current);
66
+ }
67
+ backupRef.current = null;
68
+ setEnabled(false);
69
+ }, [setList]);
70
+ const save = useCallback2(() => {
71
+ setEnabled(false);
72
+ backupRef.current = null;
73
+ onSave?.(cloneFn(list));
74
+ }, [cloneFn, list, onSave]);
75
+ return { start, cancel, save, enabled };
76
+ }
77
+
78
+ // src/react/nl2br.tsx
79
+ import jsxRuntime from "react/jsx-runtime";
80
+ function nl2br(text) {
81
+ const newlineRegex = /(\r\n|\r|\n)/g;
82
+ if (!text) return "";
83
+ const props = {};
84
+ return text.split(newlineRegex).map(function(line, index) {
85
+ if (line.match(newlineRegex)) {
86
+ return jsxRuntime.jsx("br", { key: index, ...props });
87
+ }
88
+ return line;
89
+ });
90
+ }
91
+ export {
92
+ nl2br,
93
+ useFormLayer,
94
+ useSortLayer
95
+ };