@simplysm/solid 13.0.15 → 13.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -10
- package/dist/components/data/calendar/Calendar.d.ts +5 -5
- package/dist/components/data/calendar/Calendar.d.ts.map +1 -1
- package/dist/components/data/calendar/Calendar.js.map +1 -1
- package/dist/components/data/sheet/DataSheetColumn.d.ts +1 -1
- package/dist/components/data/sheet/DataSheetColumn.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheetColumn.js.map +1 -1
- package/dist/components/data/sheet/sheetUtils.d.ts +4 -4
- package/dist/components/data/sheet/sheetUtils.d.ts.map +1 -1
- package/dist/components/data/sheet/sheetUtils.js.map +1 -1
- package/dist/components/data/sheet/types.d.ts +23 -23
- package/dist/components/data/sheet/types.d.ts.map +1 -1
- package/dist/components/disclosure/DialogInstanceContext.d.ts +3 -3
- package/dist/components/disclosure/DialogInstanceContext.d.ts.map +1 -1
- package/dist/components/disclosure/DialogInstanceContext.js.map +1 -1
- package/dist/components/form-control/checkbox/CheckboxGroup.d.ts +7 -7
- package/dist/components/form-control/checkbox/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/CheckboxGroup.js.map +1 -1
- package/dist/components/form-control/checkbox/RadioGroup.d.ts +7 -7
- package/dist/components/form-control/checkbox/RadioGroup.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/RadioGroup.js.map +1 -1
- package/dist/components/form-control/combobox/Combobox.d.ts +9 -9
- package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
- package/dist/components/form-control/combobox/ComboboxContext.d.ts +4 -4
- package/dist/components/form-control/combobox/ComboboxContext.d.ts.map +1 -1
- package/dist/components/form-control/combobox/ComboboxContext.js.map +1 -1
- package/dist/components/form-control/combobox/ComboboxItem.d.ts +2 -2
- package/dist/components/form-control/combobox/ComboboxItem.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.d.ts +16 -16
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/SelectContext.d.ts +4 -4
- package/dist/components/form-control/select/SelectContext.d.ts.map +1 -1
- package/dist/components/form-control/select/SelectContext.js.map +1 -1
- package/dist/components/form-control/select/SelectItem.d.ts +3 -3
- package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.d.ts +4 -4
- package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js.map +1 -1
- package/dist/hooks/createControllableSignal.d.ts +5 -5
- package/dist/hooks/createControllableSignal.d.ts.map +1 -1
- package/dist/hooks/createControllableSignal.js.map +1 -1
- package/dist/hooks/useLocalStorage.d.ts +1 -1
- package/dist/hooks/useLocalStorage.d.ts.map +1 -1
- package/dist/hooks/useLocalStorage.js.map +1 -1
- package/dist/hooks/useSyncConfig.d.ts +1 -1
- package/dist/hooks/useSyncConfig.d.ts.map +1 -1
- package/dist/hooks/useSyncConfig.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/InitializeProvider.d.ts +0 -1
- package/dist/providers/InitializeProvider.d.ts.map +1 -1
- package/dist/providers/InitializeProvider.js +1 -6
- package/dist/providers/InitializeProvider.js.map +2 -2
- package/dist/providers/shared-data/SharedDataContext.d.ts +10 -10
- package/dist/providers/shared-data/SharedDataContext.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataContext.js.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.d.ts +2 -2
- package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.js.map +1 -1
- package/package.json +6 -6
- package/src/components/data/calendar/Calendar.tsx +8 -8
- package/src/components/data/sheet/DataSheetColumn.tsx +1 -1
- package/src/components/data/sheet/sheetUtils.ts +16 -13
- package/src/components/data/sheet/types.ts +23 -23
- package/src/components/disclosure/DialogInstanceContext.ts +4 -4
- package/src/components/form-control/checkbox/CheckboxGroup.tsx +10 -10
- package/src/components/form-control/checkbox/RadioGroup.tsx +10 -10
- package/src/components/form-control/combobox/Combobox.tsx +9 -9
- package/src/components/form-control/combobox/ComboboxContext.ts +5 -5
- package/src/components/form-control/combobox/ComboboxItem.tsx +2 -2
- package/src/components/form-control/select/Select.tsx +20 -20
- package/src/components/form-control/select/SelectContext.ts +5 -5
- package/src/components/form-control/select/SelectItem.tsx +3 -3
- package/src/components/form-control/state-preset/StatePreset.tsx +10 -10
- package/src/hooks/createControllableSignal.ts +7 -7
- package/src/hooks/useLocalStorage.ts +11 -8
- package/src/hooks/useSyncConfig.ts +8 -5
- package/src/index.ts +58 -13
- package/src/providers/InitializeProvider.tsx +2 -5
- package/src/providers/shared-data/SharedDataContext.ts +13 -11
- package/src/providers/shared-data/SharedDataProvider.tsx +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
2
|
|
|
3
|
-
export interface DataSheetProps<
|
|
3
|
+
export interface DataSheetProps<TItem> {
|
|
4
4
|
// 데이터
|
|
5
|
-
items?:
|
|
5
|
+
items?: TItem[];
|
|
6
6
|
// 설정
|
|
7
7
|
persistKey?: string;
|
|
8
8
|
hideConfigBar?: boolean;
|
|
@@ -23,29 +23,29 @@ export interface DataSheetProps<T> {
|
|
|
23
23
|
|
|
24
24
|
// 선택
|
|
25
25
|
selectMode?: "single" | "multiple";
|
|
26
|
-
selectedItems?:
|
|
27
|
-
onSelectedItemsChange?: (items:
|
|
26
|
+
selectedItems?: TItem[];
|
|
27
|
+
onSelectedItemsChange?: (items: TItem[]) => void;
|
|
28
28
|
autoSelect?: "click";
|
|
29
|
-
isItemSelectable?: (item:
|
|
29
|
+
isItemSelectable?: (item: TItem) => boolean | string;
|
|
30
30
|
|
|
31
31
|
// 트리 확장
|
|
32
|
-
expandedItems?:
|
|
33
|
-
onExpandedItemsChange?: (items:
|
|
34
|
-
getChildren?: (item:
|
|
32
|
+
expandedItems?: TItem[];
|
|
33
|
+
onExpandedItemsChange?: (items: TItem[]) => void;
|
|
34
|
+
getChildren?: (item: TItem, index: number) => TItem[] | undefined;
|
|
35
35
|
|
|
36
36
|
// 셀 스타일
|
|
37
|
-
cellClass?: (item:
|
|
38
|
-
cellStyle?: (item:
|
|
37
|
+
cellClass?: (item: TItem, colKey: string) => string | undefined;
|
|
38
|
+
cellStyle?: (item: TItem, colKey: string) => string | undefined;
|
|
39
39
|
|
|
40
40
|
// 재정렬
|
|
41
|
-
onItemsReorder?: (event: DataSheetReorderEvent<
|
|
41
|
+
onItemsReorder?: (event: DataSheetReorderEvent<TItem>) => void;
|
|
42
42
|
|
|
43
43
|
// 기타
|
|
44
44
|
class?: string;
|
|
45
45
|
children: JSX.Element;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export interface DataSheetColumnProps<
|
|
48
|
+
export interface DataSheetColumnProps<TItem> {
|
|
49
49
|
key: string;
|
|
50
50
|
header?: string | string[];
|
|
51
51
|
headerContent?: () => JSX.Element;
|
|
@@ -59,11 +59,11 @@ export interface DataSheetColumnProps<T> {
|
|
|
59
59
|
class?: string;
|
|
60
60
|
sortable?: boolean;
|
|
61
61
|
resizable?: boolean;
|
|
62
|
-
children: (ctx: DataSheetCellContext<
|
|
62
|
+
children: (ctx: DataSheetCellContext<TItem>) => JSX.Element;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export interface DataSheetCellContext<
|
|
66
|
-
item:
|
|
65
|
+
export interface DataSheetCellContext<TItem> {
|
|
66
|
+
item: TItem;
|
|
67
67
|
index: number;
|
|
68
68
|
depth: number;
|
|
69
69
|
}
|
|
@@ -84,7 +84,7 @@ export interface DataSheetConfigColumn {
|
|
|
84
84
|
hidden?: boolean;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export interface DataSheetColumnDef<
|
|
87
|
+
export interface DataSheetColumnDef<TItem> {
|
|
88
88
|
__type: "sheet-column";
|
|
89
89
|
key: string;
|
|
90
90
|
header: string[];
|
|
@@ -99,7 +99,7 @@ export interface DataSheetColumnDef<T> {
|
|
|
99
99
|
class?: string;
|
|
100
100
|
sortable: boolean;
|
|
101
101
|
resizable: boolean;
|
|
102
|
-
cell: (ctx: DataSheetCellContext<
|
|
102
|
+
cell: (ctx: DataSheetCellContext<TItem>) => JSX.Element;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export interface HeaderDef {
|
|
@@ -114,21 +114,21 @@ export interface HeaderDef {
|
|
|
114
114
|
headerContent?: () => JSX.Element;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
export interface FlatItem<
|
|
118
|
-
item:
|
|
117
|
+
export interface FlatItem<TItem> {
|
|
118
|
+
item: TItem;
|
|
119
119
|
index: number;
|
|
120
120
|
depth: number;
|
|
121
121
|
hasChildren: boolean;
|
|
122
|
-
parent?:
|
|
122
|
+
parent?: TItem;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
// 드래그 앤 드롭 위치
|
|
126
126
|
export type DataSheetDragPosition = "before" | "after" | "inside";
|
|
127
127
|
|
|
128
128
|
// 재정렬 이벤트
|
|
129
|
-
export interface DataSheetReorderEvent<
|
|
130
|
-
item:
|
|
131
|
-
targetItem:
|
|
129
|
+
export interface DataSheetReorderEvent<TItem> {
|
|
130
|
+
item: TItem;
|
|
131
|
+
targetItem: TItem;
|
|
132
132
|
position: DataSheetDragPosition;
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createContext, useContext } from "solid-js";
|
|
2
2
|
|
|
3
|
-
export interface DialogInstance<
|
|
4
|
-
close: (result?:
|
|
3
|
+
export interface DialogInstance<TResult> {
|
|
4
|
+
close: (result?: TResult) => void;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export const DialogInstanceContext = createContext<DialogInstance<unknown>>();
|
|
8
8
|
|
|
9
|
-
export function useDialogInstance<
|
|
10
|
-
return useContext(DialogInstanceContext) as DialogInstance<
|
|
9
|
+
export function useDialogInstance<TResult = undefined>(): DialogInstance<TResult> | undefined {
|
|
10
|
+
return useContext(DialogInstanceContext) as DialogInstance<TResult> | undefined;
|
|
11
11
|
}
|
|
@@ -4,9 +4,9 @@ import { createControllableSignal } from "../../../hooks/createControllableSigna
|
|
|
4
4
|
import { Checkbox } from "./Checkbox";
|
|
5
5
|
import type { CheckboxSize, CheckboxTheme } from "./Checkbox.styles";
|
|
6
6
|
|
|
7
|
-
interface CheckboxGroupContextValue<
|
|
8
|
-
value: () =>
|
|
9
|
-
toggle: (item:
|
|
7
|
+
interface CheckboxGroupContextValue<TValue> {
|
|
8
|
+
value: () => TValue[];
|
|
9
|
+
toggle: (item: TValue) => void;
|
|
10
10
|
disabled: () => boolean;
|
|
11
11
|
size: () => CheckboxSize | undefined;
|
|
12
12
|
theme: () => CheckboxTheme | undefined;
|
|
@@ -18,13 +18,13 @@ const CheckboxGroupContext = createContext<CheckboxGroupContextValue<any>>();
|
|
|
18
18
|
|
|
19
19
|
// --- CheckboxGroup.Item ---
|
|
20
20
|
|
|
21
|
-
interface CheckboxGroupItemProps<
|
|
22
|
-
value:
|
|
21
|
+
interface CheckboxGroupItemProps<TValue> {
|
|
22
|
+
value: TValue;
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
children?: JSX.Element;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function CheckboxGroupItemInner<
|
|
27
|
+
function CheckboxGroupItemInner<TValue>(props: CheckboxGroupItemProps<TValue>) {
|
|
28
28
|
const ctx = useContext(CheckboxGroupContext);
|
|
29
29
|
if (!ctx) throw new Error("CheckboxGroup.Item은 CheckboxGroup 내부에서만 사용할 수 있습니다");
|
|
30
30
|
|
|
@@ -47,9 +47,9 @@ function CheckboxGroupItemInner<T>(props: CheckboxGroupItemProps<T>) {
|
|
|
47
47
|
|
|
48
48
|
// --- CheckboxGroup ---
|
|
49
49
|
|
|
50
|
-
interface CheckboxGroupProps<
|
|
51
|
-
value?:
|
|
52
|
-
onValueChange?: (value:
|
|
50
|
+
interface CheckboxGroupProps<TValue> {
|
|
51
|
+
value?: TValue[];
|
|
52
|
+
onValueChange?: (value: TValue[]) => void;
|
|
53
53
|
disabled?: boolean;
|
|
54
54
|
size?: CheckboxSize;
|
|
55
55
|
theme?: CheckboxTheme;
|
|
@@ -61,7 +61,7 @@ interface CheckboxGroupProps<T> {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
interface CheckboxGroupComponent {
|
|
64
|
-
<
|
|
64
|
+
<TValue = unknown>(props: CheckboxGroupProps<TValue>): JSX.Element;
|
|
65
65
|
Item: typeof CheckboxGroupItemInner;
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -4,9 +4,9 @@ import { createControllableSignal } from "../../../hooks/createControllableSigna
|
|
|
4
4
|
import { Radio } from "./Radio";
|
|
5
5
|
import type { CheckboxSize, CheckboxTheme } from "./Checkbox.styles";
|
|
6
6
|
|
|
7
|
-
interface RadioGroupContextValue<
|
|
8
|
-
value: () =>
|
|
9
|
-
select: (item:
|
|
7
|
+
interface RadioGroupContextValue<TValue> {
|
|
8
|
+
value: () => TValue | undefined;
|
|
9
|
+
select: (item: TValue) => void;
|
|
10
10
|
disabled: () => boolean;
|
|
11
11
|
size: () => CheckboxSize | undefined;
|
|
12
12
|
theme: () => CheckboxTheme | undefined;
|
|
@@ -18,13 +18,13 @@ const RadioGroupContext = createContext<RadioGroupContextValue<any>>();
|
|
|
18
18
|
|
|
19
19
|
// --- RadioGroup.Item ---
|
|
20
20
|
|
|
21
|
-
interface RadioGroupItemProps<
|
|
22
|
-
value:
|
|
21
|
+
interface RadioGroupItemProps<TValue> {
|
|
22
|
+
value: TValue;
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
children?: JSX.Element;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function RadioGroupItemInner<
|
|
27
|
+
function RadioGroupItemInner<TValue>(props: RadioGroupItemProps<TValue>) {
|
|
28
28
|
const ctx = useContext(RadioGroupContext);
|
|
29
29
|
if (!ctx) throw new Error("RadioGroup.Item은 RadioGroup 내부에서만 사용할 수 있습니다");
|
|
30
30
|
|
|
@@ -47,9 +47,9 @@ function RadioGroupItemInner<T>(props: RadioGroupItemProps<T>) {
|
|
|
47
47
|
|
|
48
48
|
// --- RadioGroup ---
|
|
49
49
|
|
|
50
|
-
interface RadioGroupProps<
|
|
51
|
-
value?:
|
|
52
|
-
onValueChange?: (value:
|
|
50
|
+
interface RadioGroupProps<TValue> {
|
|
51
|
+
value?: TValue;
|
|
52
|
+
onValueChange?: (value: TValue) => void;
|
|
53
53
|
disabled?: boolean;
|
|
54
54
|
size?: CheckboxSize;
|
|
55
55
|
theme?: CheckboxTheme;
|
|
@@ -61,7 +61,7 @@ interface RadioGroupProps<T> {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
interface RadioGroupComponent {
|
|
64
|
-
<
|
|
64
|
+
<TValue = unknown>(props: RadioGroupProps<TValue>): JSX.Element;
|
|
65
65
|
Item: typeof RadioGroupItemInner;
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -28,8 +28,8 @@ const noResultsClass = clsx("px-3 py-2", textMuted);
|
|
|
28
28
|
/**
|
|
29
29
|
* Combobox 아이템 렌더링 템플릿
|
|
30
30
|
*/
|
|
31
|
-
interface ComboboxItemTemplateProps<
|
|
32
|
-
children: (item:
|
|
31
|
+
interface ComboboxItemTemplateProps<TItem> {
|
|
32
|
+
children: (item: TItem, index: number) => JSX.Element;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// 템플릿 함수를 저장하는 전역 WeakMap
|
|
@@ -46,15 +46,15 @@ const ComboboxItemTemplate = <T,>(props: ComboboxItemTemplateProps<T>) => (
|
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
// Props 정의
|
|
49
|
-
export interface ComboboxProps<
|
|
49
|
+
export interface ComboboxProps<TValue = unknown> {
|
|
50
50
|
/** 현재 선택된 값 */
|
|
51
|
-
value?:
|
|
51
|
+
value?: TValue;
|
|
52
52
|
|
|
53
53
|
/** 값 변경 콜백 */
|
|
54
|
-
onValueChange?: (value:
|
|
54
|
+
onValueChange?: (value: TValue) => void;
|
|
55
55
|
|
|
56
56
|
/** 아이템 로드 함수 (필수) */
|
|
57
|
-
loadItems: (query: string) => Promise<
|
|
57
|
+
loadItems: (query: string) => Promise<TValue[]>;
|
|
58
58
|
|
|
59
59
|
/** 디바운스 딜레이 (기본값: 300ms) */
|
|
60
60
|
debounceMs?: number;
|
|
@@ -63,10 +63,10 @@ export interface ComboboxProps<T = unknown> {
|
|
|
63
63
|
allowCustomValue?: boolean;
|
|
64
64
|
|
|
65
65
|
/** 커스텀 값 파싱 함수 */
|
|
66
|
-
parseCustomValue?: (text: string) =>
|
|
66
|
+
parseCustomValue?: (text: string) => TValue;
|
|
67
67
|
|
|
68
68
|
/** 선택된 값을 렌더링하는 함수 (필수) */
|
|
69
|
-
renderValue: (value:
|
|
69
|
+
renderValue: (value: TValue) => JSX.Element;
|
|
70
70
|
|
|
71
71
|
/** 비활성화 */
|
|
72
72
|
disabled?: boolean;
|
|
@@ -94,7 +94,7 @@ export interface ComboboxProps<T = unknown> {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
interface ComboboxComponent {
|
|
97
|
-
<
|
|
97
|
+
<TValue = unknown>(props: ComboboxProps<TValue>): JSX.Element;
|
|
98
98
|
Item: typeof ComboboxItem;
|
|
99
99
|
ItemTemplate: typeof ComboboxItemTemplate;
|
|
100
100
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createContext, useContext } from "solid-js";
|
|
2
2
|
|
|
3
|
-
export interface ComboboxContextValue<
|
|
3
|
+
export interface ComboboxContextValue<TValue = unknown> {
|
|
4
4
|
/** 값이 선택되어 있는지 확인 */
|
|
5
|
-
isSelected: (value:
|
|
5
|
+
isSelected: (value: TValue) => boolean;
|
|
6
6
|
|
|
7
7
|
/** 값 선택 */
|
|
8
|
-
selectValue: (value:
|
|
8
|
+
selectValue: (value: TValue) => void;
|
|
9
9
|
|
|
10
10
|
/** 드롭다운 닫기 */
|
|
11
11
|
closeDropdown: () => void;
|
|
@@ -13,10 +13,10 @@ export interface ComboboxContextValue<T = unknown> {
|
|
|
13
13
|
|
|
14
14
|
export const ComboboxContext = createContext<ComboboxContextValue>();
|
|
15
15
|
|
|
16
|
-
export function useComboboxContext<
|
|
16
|
+
export function useComboboxContext<TValue = unknown>(): ComboboxContextValue<TValue> {
|
|
17
17
|
const context = useContext(ComboboxContext);
|
|
18
18
|
if (!context) {
|
|
19
19
|
throw new Error("useComboboxContext는 Combobox 컴포넌트 내부에서만 사용할 수 있습니다");
|
|
20
20
|
}
|
|
21
|
-
return context as ComboboxContextValue<
|
|
21
|
+
return context as ComboboxContextValue<TValue>;
|
|
22
22
|
}
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
|
|
12
12
|
void ripple;
|
|
13
13
|
|
|
14
|
-
export interface ComboboxItemProps<
|
|
14
|
+
export interface ComboboxItemProps<TValue = unknown> extends Omit<
|
|
15
15
|
JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
16
16
|
"value" | "onClick"
|
|
17
17
|
> {
|
|
18
18
|
/** 아이템의 값 */
|
|
19
|
-
value:
|
|
19
|
+
value: TValue;
|
|
20
20
|
|
|
21
21
|
/** 비활성화 */
|
|
22
22
|
disabled?: boolean;
|
|
@@ -65,8 +65,8 @@ const SelectHeader: ParentComponent = (props) => <div data-select-header>{props.
|
|
|
65
65
|
*
|
|
66
66
|
* 함수 참조를 저장하기 위해 전역 Map 사용
|
|
67
67
|
*/
|
|
68
|
-
interface SelectItemTemplateProps<
|
|
69
|
-
children: (item:
|
|
68
|
+
interface SelectItemTemplateProps<TValue> {
|
|
69
|
+
children: (item: TValue, index: number, depth: number) => JSX.Element;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
// 템플릿 함수를 저장하는 전역 Map (WeakMap 사용하여 메모리 누수 방지)
|
|
@@ -109,15 +109,15 @@ interface SelectCommonProps {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// 단일 선택 Props
|
|
112
|
-
interface SelectSingleBaseProps<
|
|
112
|
+
interface SelectSingleBaseProps<TValue> extends SelectCommonProps {
|
|
113
113
|
/** 다중 선택 모드 */
|
|
114
114
|
multiple?: false;
|
|
115
115
|
|
|
116
116
|
/** 현재 선택된 값 */
|
|
117
|
-
value?:
|
|
117
|
+
value?: TValue;
|
|
118
118
|
|
|
119
119
|
/** 값 변경 콜백 */
|
|
120
|
-
onValueChange?: (value:
|
|
120
|
+
onValueChange?: (value: TValue) => void;
|
|
121
121
|
|
|
122
122
|
/** 다중 선택 시 표시 방향 (단일 선택에서는 사용 안 함) */
|
|
123
123
|
multiDisplayDirection?: never;
|
|
@@ -127,15 +127,15 @@ interface SelectSingleBaseProps<T> extends SelectCommonProps {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
// 다중 선택 Props
|
|
130
|
-
interface SelectMultipleBaseProps<
|
|
130
|
+
interface SelectMultipleBaseProps<TValue> extends SelectCommonProps {
|
|
131
131
|
/** 다중 선택 모드 */
|
|
132
132
|
multiple: true;
|
|
133
133
|
|
|
134
134
|
/** 현재 선택된 값 */
|
|
135
|
-
value?:
|
|
135
|
+
value?: TValue[];
|
|
136
136
|
|
|
137
137
|
/** 값 변경 콜백 */
|
|
138
|
-
onValueChange?: (value:
|
|
138
|
+
onValueChange?: (value: TValue[]) => void;
|
|
139
139
|
|
|
140
140
|
/** 다중 선택 시 표시 방향 */
|
|
141
141
|
multiDisplayDirection?: "horizontal" | "vertical";
|
|
@@ -145,29 +145,29 @@ interface SelectMultipleBaseProps<T> extends SelectCommonProps {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// items 방식
|
|
148
|
-
interface SelectWithItemsPropsBase<
|
|
149
|
-
items:
|
|
150
|
-
getChildren?: (item:
|
|
151
|
-
renderValue?: (value:
|
|
148
|
+
interface SelectWithItemsPropsBase<TValue> {
|
|
149
|
+
items: TValue[];
|
|
150
|
+
getChildren?: (item: TValue, index: number, depth: number) => TValue[] | undefined;
|
|
151
|
+
renderValue?: (value: TValue) => JSX.Element;
|
|
152
152
|
children?: JSX.Element;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// children 방식
|
|
156
|
-
interface SelectWithChildrenPropsBase<
|
|
156
|
+
interface SelectWithChildrenPropsBase<TValue> {
|
|
157
157
|
items?: never;
|
|
158
158
|
getChildren?: never;
|
|
159
|
-
renderValue: (value:
|
|
159
|
+
renderValue: (value: TValue) => JSX.Element;
|
|
160
160
|
children: JSX.Element;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
export type SelectProps<
|
|
164
|
-
| (SelectSingleBaseProps<
|
|
165
|
-
| (SelectSingleBaseProps<
|
|
166
|
-
| (SelectMultipleBaseProps<
|
|
167
|
-
| (SelectMultipleBaseProps<
|
|
163
|
+
export type SelectProps<TValue = unknown> =
|
|
164
|
+
| (SelectSingleBaseProps<TValue> & SelectWithItemsPropsBase<TValue>)
|
|
165
|
+
| (SelectSingleBaseProps<TValue> & SelectWithChildrenPropsBase<TValue>)
|
|
166
|
+
| (SelectMultipleBaseProps<TValue> & SelectWithItemsPropsBase<TValue>)
|
|
167
|
+
| (SelectMultipleBaseProps<TValue> & SelectWithChildrenPropsBase<TValue>);
|
|
168
168
|
|
|
169
169
|
interface SelectComponent {
|
|
170
|
-
<
|
|
170
|
+
<TValue = unknown>(props: SelectProps<TValue>): JSX.Element;
|
|
171
171
|
Item: typeof SelectItem;
|
|
172
172
|
Action: typeof SelectAction;
|
|
173
173
|
Header: typeof SelectHeader;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createContext, useContext, type Accessor } from "solid-js";
|
|
2
2
|
|
|
3
|
-
export interface SelectContextValue<
|
|
3
|
+
export interface SelectContextValue<TValue = unknown> {
|
|
4
4
|
/** 다중 선택 모드 여부 */
|
|
5
5
|
multiple: Accessor<boolean>;
|
|
6
6
|
|
|
7
7
|
/** 값이 선택되어 있는지 확인 */
|
|
8
|
-
isSelected: (value:
|
|
8
|
+
isSelected: (value: TValue) => boolean;
|
|
9
9
|
|
|
10
10
|
/** 값 선택/해제 토글 */
|
|
11
|
-
toggleValue: (value:
|
|
11
|
+
toggleValue: (value: TValue) => void;
|
|
12
12
|
|
|
13
13
|
/** 드롭다운 닫기 */
|
|
14
14
|
closeDropdown: () => void;
|
|
@@ -16,10 +16,10 @@ export interface SelectContextValue<T = unknown> {
|
|
|
16
16
|
|
|
17
17
|
export const SelectContext = createContext<SelectContextValue>();
|
|
18
18
|
|
|
19
|
-
export function useSelectContext<
|
|
19
|
+
export function useSelectContext<TValue = unknown>(): SelectContextValue<TValue> {
|
|
20
20
|
const context = useContext(SelectContext);
|
|
21
21
|
if (!context) {
|
|
22
22
|
throw new Error("useSelectContext는 Select 컴포넌트 내부에서만 사용할 수 있습니다");
|
|
23
23
|
}
|
|
24
|
-
return context as SelectContextValue<
|
|
24
|
+
return context as SelectContextValue<TValue>;
|
|
25
25
|
}
|
|
@@ -30,18 +30,18 @@ const SelectItemChildren: ParentComponent = (props) => (
|
|
|
30
30
|
</div>
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
-
export interface SelectItemProps<
|
|
33
|
+
export interface SelectItemProps<TValue = unknown> extends Omit<
|
|
34
34
|
JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
35
35
|
"value" | "onClick"
|
|
36
36
|
> {
|
|
37
37
|
/** 아이템의 값 */
|
|
38
|
-
value:
|
|
38
|
+
value: TValue;
|
|
39
39
|
|
|
40
40
|
/** 비활성화 */
|
|
41
41
|
disabled?: boolean;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
interface SelectItemComponent<
|
|
44
|
+
interface SelectItemComponent<TValue = unknown> extends ParentComponent<SelectItemProps<TValue>> {
|
|
45
45
|
Children: typeof SelectItemChildren;
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -12,17 +12,17 @@ import type { ComponentSize } from "../../../styles/tokens.styles";
|
|
|
12
12
|
|
|
13
13
|
// ── Types ──
|
|
14
14
|
|
|
15
|
-
interface StatePresetItem<
|
|
15
|
+
interface StatePresetItem<TValue> {
|
|
16
16
|
name: string;
|
|
17
|
-
state:
|
|
17
|
+
state: TValue;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
type StatePresetSize = ComponentSize;
|
|
21
21
|
|
|
22
|
-
export interface StatePresetProps<
|
|
22
|
+
export interface StatePresetProps<TValue> {
|
|
23
23
|
presetKey: string;
|
|
24
|
-
value:
|
|
25
|
-
onValueChange: (value:
|
|
24
|
+
value: TValue;
|
|
25
|
+
onValueChange: (value: TValue) => void;
|
|
26
26
|
size?: StatePresetSize;
|
|
27
27
|
class?: string;
|
|
28
28
|
style?: JSX.CSSProperties;
|
|
@@ -107,14 +107,14 @@ const iconSize = "0.85em";
|
|
|
107
107
|
|
|
108
108
|
// ── Component ──
|
|
109
109
|
|
|
110
|
-
function StatePresetInner<
|
|
110
|
+
function StatePresetInner<TValue>(props: StatePresetProps<TValue>): JSX.Element {
|
|
111
111
|
const [local] = splitProps(props, ["presetKey", "value", "onValueChange", "size", "class", "style"]);
|
|
112
112
|
|
|
113
113
|
const notification = useNotification();
|
|
114
114
|
|
|
115
115
|
// presetKey는 마운트 시 한 번만 설정되는 식별자이므로 즉시 평가하여 캡처
|
|
116
116
|
/* eslint-disable solid/reactivity */
|
|
117
|
-
const [presets, setPresets] = useSyncConfig<StatePresetItem<
|
|
117
|
+
const [presets, setPresets] = useSyncConfig<StatePresetItem<TValue>[]>(`state-preset.${local.presetKey}`, []);
|
|
118
118
|
/* eslint-enable solid/reactivity */
|
|
119
119
|
const [adding, setAdding] = createSignal(false);
|
|
120
120
|
const [inputValue, setInputValue] = createSignal("");
|
|
@@ -143,7 +143,7 @@ function StatePresetInner<T>(props: StatePresetProps<T>): JSX.Element {
|
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
const newPreset: StatePresetItem<
|
|
146
|
+
const newPreset: StatePresetItem<TValue> = {
|
|
147
147
|
name,
|
|
148
148
|
state: objClone(local.value),
|
|
149
149
|
};
|
|
@@ -153,7 +153,7 @@ function StatePresetInner<T>(props: StatePresetProps<T>): JSX.Element {
|
|
|
153
153
|
setInputValue("");
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
function handleRestore(preset: StatePresetItem<
|
|
156
|
+
function handleRestore(preset: StatePresetItem<TValue>): void {
|
|
157
157
|
if (!objEqual(local.value, preset.state)) {
|
|
158
158
|
local.onValueChange(objClone(preset.state));
|
|
159
159
|
}
|
|
@@ -278,4 +278,4 @@ function StatePresetInner<T>(props: StatePresetProps<T>): JSX.Element {
|
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
export const StatePreset = StatePresetInner as <
|
|
281
|
+
export const StatePreset = StatePresetInner as <TValue>(props: StatePresetProps<TValue>) => JSX.Element;
|
|
@@ -7,7 +7,7 @@ import { createSignal, createEffect } from "solid-js";
|
|
|
7
7
|
* @remarks
|
|
8
8
|
* 함수를 저장해야 할 경우 객체로 감싸기: `createControllableSignal<{ fn: () => void }>(...)`
|
|
9
9
|
*/
|
|
10
|
-
type NotFunction<
|
|
10
|
+
type NotFunction<TValue> = TValue extends (...args: unknown[]) => unknown ? never : TValue;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Controlled/Uncontrolled 패턴을 지원하는 signal hook
|
|
@@ -35,11 +35,11 @@ type NotFunction<T> = T extends (...args: unknown[]) => unknown ? never : T;
|
|
|
35
35
|
* setOpen(prev => !prev);
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
|
-
export function createControllableSignal<
|
|
39
|
-
value: () =>
|
|
40
|
-
onChange: () => ((value:
|
|
38
|
+
export function createControllableSignal<TValue>(options: {
|
|
39
|
+
value: () => TValue & NotFunction<TValue>;
|
|
40
|
+
onChange: () => ((value: TValue) => void) | undefined;
|
|
41
41
|
}) {
|
|
42
|
-
const [internalValue, setInternalValue] = createSignal<
|
|
42
|
+
const [internalValue, setInternalValue] = createSignal<TValue>(options.value());
|
|
43
43
|
|
|
44
44
|
// props 변경 시 내부 상태 동기화 (props 우선)
|
|
45
45
|
createEffect(() => {
|
|
@@ -49,8 +49,8 @@ export function createControllableSignal<T>(options: {
|
|
|
49
49
|
|
|
50
50
|
const isControlled = () => options.onChange() !== undefined;
|
|
51
51
|
const value = () => (isControlled() ? options.value() : internalValue());
|
|
52
|
-
const setValue = (newValue:
|
|
53
|
-
const resolved = typeof newValue === "function" ? (newValue as (prev:
|
|
52
|
+
const setValue = (newValue: TValue | ((prev: TValue) => TValue)) => {
|
|
53
|
+
const resolved = typeof newValue === "function" ? (newValue as (prev: TValue) => TValue)(value()) : newValue;
|
|
54
54
|
|
|
55
55
|
if (isControlled()) {
|
|
56
56
|
options.onChange()?.(resolved);
|
|
@@ -27,28 +27,31 @@ import { useConfig } from "../providers/ConfigContext";
|
|
|
27
27
|
* setToken(undefined);
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
|
-
export function useLocalStorage<
|
|
30
|
+
export function useLocalStorage<TValue>(
|
|
31
|
+
key: string,
|
|
32
|
+
initialValue?: TValue,
|
|
33
|
+
): [Accessor<TValue | undefined>, Setter<TValue | undefined>] {
|
|
31
34
|
const config = useConfig();
|
|
32
35
|
const prefixedKey = `${config.clientName}.${key}`;
|
|
33
36
|
|
|
34
37
|
// localStorage에서 초기값 읽기
|
|
35
|
-
let storedValue:
|
|
38
|
+
let storedValue: TValue | undefined = initialValue;
|
|
36
39
|
try {
|
|
37
40
|
const item = localStorage.getItem(prefixedKey);
|
|
38
41
|
if (item !== null) {
|
|
39
|
-
storedValue = JSON.parse(item) as
|
|
42
|
+
storedValue = JSON.parse(item) as TValue;
|
|
40
43
|
}
|
|
41
44
|
} catch {
|
|
42
45
|
// JSON 파싱 실패 시 초기값 사용
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const [value, setValue] = createSignal<
|
|
48
|
+
const [value, setValue] = createSignal<TValue | undefined>(storedValue);
|
|
46
49
|
|
|
47
|
-
const setAndStore = (newValue:
|
|
48
|
-
let resolved:
|
|
50
|
+
const setAndStore = (newValue: TValue | undefined | ((prev: TValue | undefined) => TValue | undefined)) => {
|
|
51
|
+
let resolved: TValue | undefined;
|
|
49
52
|
|
|
50
53
|
if (typeof newValue === "function") {
|
|
51
|
-
resolved = (newValue as (prev:
|
|
54
|
+
resolved = (newValue as (prev: TValue | undefined) => TValue | undefined)(value());
|
|
52
55
|
setValue(() => resolved);
|
|
53
56
|
} else {
|
|
54
57
|
resolved = newValue;
|
|
@@ -64,5 +67,5 @@ export function useLocalStorage<T>(key: string, initialValue?: T): [Accessor<T |
|
|
|
64
67
|
return resolved;
|
|
65
68
|
};
|
|
66
69
|
|
|
67
|
-
return [value, setAndStore as Setter<
|
|
70
|
+
return [value, setAndStore as Setter<TValue | undefined>];
|
|
68
71
|
}
|
|
@@ -22,10 +22,13 @@ import { useConfig } from "../providers/ConfigContext";
|
|
|
22
22
|
* </Show>
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
export function useSyncConfig<
|
|
25
|
+
export function useSyncConfig<TValue>(
|
|
26
|
+
key: string,
|
|
27
|
+
defaultValue: TValue,
|
|
28
|
+
): [Accessor<TValue>, Setter<TValue>, Accessor<boolean>] {
|
|
26
29
|
const config = useConfig();
|
|
27
30
|
const prefixedKey = `${config.clientName}.${key}`;
|
|
28
|
-
const [value, setValue] = createSignal<
|
|
31
|
+
const [value, setValue] = createSignal<TValue>(defaultValue);
|
|
29
32
|
const [loading, setLoading] = createSignal(false);
|
|
30
33
|
|
|
31
34
|
// Initialize from storage
|
|
@@ -35,7 +38,7 @@ export function useSyncConfig<T>(key: string, defaultValue: T): [Accessor<T>, Se
|
|
|
35
38
|
try {
|
|
36
39
|
const stored = localStorage.getItem(prefixedKey);
|
|
37
40
|
if (stored !== null) {
|
|
38
|
-
setValue(() => JSON.parse(stored) as
|
|
41
|
+
setValue(() => JSON.parse(stored) as TValue);
|
|
39
42
|
}
|
|
40
43
|
} catch {
|
|
41
44
|
// Ignore parse errors, keep default value
|
|
@@ -48,14 +51,14 @@ export function useSyncConfig<T>(key: string, defaultValue: T): [Accessor<T>, Se
|
|
|
48
51
|
try {
|
|
49
52
|
const stored = await config.syncStorage.getItem(prefixedKey);
|
|
50
53
|
if (stored !== null) {
|
|
51
|
-
setValue(() => JSON.parse(stored) as
|
|
54
|
+
setValue(() => JSON.parse(stored) as TValue);
|
|
52
55
|
}
|
|
53
56
|
} catch {
|
|
54
57
|
// Fall back to localStorage on error
|
|
55
58
|
try {
|
|
56
59
|
const stored = localStorage.getItem(prefixedKey);
|
|
57
60
|
if (stored !== null) {
|
|
58
|
-
setValue(() => JSON.parse(stored) as
|
|
61
|
+
setValue(() => JSON.parse(stored) as TValue);
|
|
59
62
|
}
|
|
60
63
|
} catch {
|
|
61
64
|
// Ignore parse errors
|