@simplysm/solid 13.0.62 → 13.0.65
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 +6 -0
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +3 -2
- package/dist/components/data/sheet/DataSheet.js.map +2 -2
- package/dist/components/features/address/AddressSearch.d.ts +8 -0
- package/dist/components/features/address/AddressSearch.d.ts.map +1 -0
- package/dist/components/features/address/AddressSearch.js +72 -0
- package/dist/components/features/address/AddressSearch.js.map +6 -0
- package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-detail/CrudDetail.js +62 -41
- package/dist/components/features/crud-detail/CrudDetail.js.map +6 -0
- package/dist/components/features/crud-detail/CrudDetailAfter.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-detail/CrudDetailAfter.js.map +1 -1
- package/dist/components/features/crud-detail/CrudDetailBefore.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-detail/CrudDetailBefore.js.map +1 -1
- package/dist/components/features/crud-detail/CrudDetailTools.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-detail/CrudDetailTools.js.map +1 -1
- package/dist/components/features/crud-detail/types.d.ts.map +1 -0
- package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-sheet/CrudSheet.js +166 -21
- package/dist/components/features/crud-sheet/CrudSheet.js.map +6 -0
- package/dist/components/features/crud-sheet/CrudSheetColumn.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-sheet/CrudSheetColumn.js +1 -1
- package/dist/components/{data → features}/crud-sheet/CrudSheetColumn.js.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheetFilter.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-sheet/CrudSheetFilter.js.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheetHeader.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-sheet/CrudSheetHeader.js.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheetTools.d.ts.map +1 -0
- package/dist/components/{data → features}/crud-sheet/CrudSheetTools.js.map +1 -1
- package/dist/components/{data → features}/crud-sheet/types.d.ts +10 -4
- package/dist/components/features/crud-sheet/types.d.ts.map +1 -0
- package/dist/components/features/data-select-button/DataSelectButton.d.ts +38 -0
- package/dist/components/features/data-select-button/DataSelectButton.d.ts.map +1 -0
- package/dist/components/features/data-select-button/DataSelectButton.js +184 -0
- package/dist/components/features/data-select-button/DataSelectButton.js.map +6 -0
- package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -0
- package/dist/components/{data → features}/permission-table/PermissionTable.js +1 -1
- package/dist/components/{data → features}/permission-table/PermissionTable.js.map +1 -1
- package/dist/components/features/shared-data/SharedDataSelect.d.ts +32 -0
- package/dist/components/features/shared-data/SharedDataSelect.d.ts.map +1 -0
- package/dist/components/features/shared-data/SharedDataSelect.js +74 -0
- package/dist/components/features/shared-data/SharedDataSelect.js.map +6 -0
- package/dist/components/features/shared-data/SharedDataSelectButton.d.ts +29 -0
- package/dist/components/features/shared-data/SharedDataSelectButton.d.ts.map +1 -0
- package/dist/components/features/shared-data/SharedDataSelectButton.js +17 -0
- package/dist/components/features/shared-data/SharedDataSelectButton.js.map +6 -0
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts +29 -0
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -0
- package/dist/components/features/shared-data/SharedDataSelectList.js +80 -0
- package/dist/components/features/shared-data/SharedDataSelectList.js.map +6 -0
- package/dist/components/form-control/checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.js +10 -10
- package/dist/components/form-control/checkbox/Checkbox.js.map +2 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.styles.js +2 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.js.map +1 -1
- package/dist/components/form-control/checkbox/Radio.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Radio.js +13 -13
- package/dist/components/form-control/checkbox/Radio.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts +7 -3
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +146 -45
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/select-list/SelectList.d.ts +54 -0
- package/dist/components/form-control/select-list/SelectList.d.ts.map +1 -0
- package/dist/components/form-control/select-list/SelectList.js +280 -0
- package/dist/components/form-control/select-list/SelectList.js.map +6 -0
- package/dist/components/form-control/select-list/SelectListContext.d.ts +13 -0
- package/dist/components/form-control/select-list/SelectListContext.d.ts.map +1 -0
- package/dist/components/form-control/select-list/SelectListContext.js +14 -0
- package/dist/components/form-control/select-list/SelectListContext.js.map +6 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/providers/ServiceClientContext.d.ts +5 -5
- package/dist/providers/ServiceClientContext.d.ts.map +1 -1
- package/dist/providers/ServiceClientProvider.d.ts.map +1 -1
- package/dist/providers/ServiceClientProvider.js +12 -8
- package/dist/providers/ServiceClientProvider.js.map +2 -2
- package/dist/providers/shared-data/SharedDataContext.d.ts +16 -2
- 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 +1 -2
- package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.js +27 -13
- package/dist/providers/shared-data/SharedDataProvider.js.map +2 -2
- package/docs/data-components.md +15 -4
- package/docs/form-controls.md +257 -0
- package/docs/hooks.md +30 -0
- package/docs/providers.md +7 -0
- package/package.json +5 -3
- package/src/components/data/sheet/DataSheet.tsx +6 -7
- package/src/components/features/address/AddressSearch.tsx +75 -0
- package/src/components/{data → features}/crud-detail/CrudDetail.tsx +51 -26
- package/src/components/{data → features}/crud-sheet/CrudSheet.tsx +160 -23
- package/src/components/{data → features}/crud-sheet/CrudSheetColumn.tsx +1 -1
- package/src/components/{data → features}/crud-sheet/types.ts +14 -4
- package/src/components/features/data-select-button/DataSelectButton.tsx +279 -0
- package/src/components/{data → features}/permission-table/PermissionTable.tsx +1 -1
- package/src/components/features/shared-data/SharedDataSelect.tsx +101 -0
- package/src/components/features/shared-data/SharedDataSelectButton.tsx +47 -0
- package/src/components/features/shared-data/SharedDataSelectList.tsx +85 -0
- package/src/components/form-control/checkbox/Checkbox.styles.ts +2 -2
- package/src/components/form-control/checkbox/Checkbox.tsx +18 -20
- package/src/components/form-control/checkbox/Radio.tsx +18 -20
- package/src/components/form-control/select/Select.tsx +192 -36
- package/src/components/form-control/select-list/SelectList.tsx +385 -0
- package/src/components/form-control/select-list/SelectListContext.ts +23 -0
- package/src/index.ts +29 -5
- package/src/providers/ServiceClientContext.ts +5 -5
- package/src/providers/ServiceClientProvider.tsx +17 -12
- package/src/providers/shared-data/SharedDataContext.ts +16 -2
- package/src/providers/shared-data/SharedDataProvider.tsx +33 -17
- package/dist/components/data/crud-detail/CrudDetail.d.ts.map +0 -1
- package/dist/components/data/crud-detail/CrudDetail.js.map +0 -6
- package/dist/components/data/crud-detail/CrudDetailAfter.d.ts.map +0 -1
- package/dist/components/data/crud-detail/CrudDetailBefore.d.ts.map +0 -1
- package/dist/components/data/crud-detail/CrudDetailTools.d.ts.map +0 -1
- package/dist/components/data/crud-detail/types.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/CrudSheet.js.map +0 -6
- package/dist/components/data/crud-sheet/CrudSheetColumn.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/CrudSheetFilter.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/CrudSheetHeader.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/CrudSheetTools.d.ts.map +0 -1
- package/dist/components/data/crud-sheet/types.d.ts.map +0 -1
- package/dist/components/data/permission-table/PermissionTable.d.ts.map +0 -1
- /package/dist/components/{data → features}/crud-detail/CrudDetail.d.ts +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailAfter.d.ts +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailAfter.js +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailBefore.d.ts +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailBefore.js +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailTools.d.ts +0 -0
- /package/dist/components/{data → features}/crud-detail/CrudDetailTools.js +0 -0
- /package/dist/components/{data → features}/crud-detail/types.d.ts +0 -0
- /package/dist/components/{data → features}/crud-detail/types.js +0 -0
- /package/dist/components/{data → features}/crud-detail/types.js.map +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheet.d.ts +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetColumn.d.ts +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetFilter.d.ts +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetFilter.js +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetHeader.d.ts +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetHeader.js +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetTools.d.ts +0 -0
- /package/dist/components/{data → features}/crud-sheet/CrudSheetTools.js +0 -0
- /package/dist/components/{data → features}/crud-sheet/types.js +0 -0
- /package/dist/components/{data → features}/crud-sheet/types.js.map +0 -0
- /package/dist/components/{data → features}/permission-table/PermissionTable.d.ts +0 -0
- /package/src/components/{data → features}/crud-detail/CrudDetailAfter.tsx +0 -0
- /package/src/components/{data → features}/crud-detail/CrudDetailBefore.tsx +0 -0
- /package/src/components/{data → features}/crud-detail/CrudDetailTools.tsx +0 -0
- /package/src/components/{data → features}/crud-detail/types.ts +0 -0
- /package/src/components/{data → features}/crud-sheet/CrudSheetFilter.tsx +0 -0
- /package/src/components/{data → features}/crud-sheet/CrudSheetHeader.tsx +0 -0
- /package/src/components/{data → features}/crud-sheet/CrudSheetTools.tsx +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
children,
|
|
3
|
+
createEffect,
|
|
3
4
|
createMemo,
|
|
4
5
|
createSignal,
|
|
5
6
|
For,
|
|
@@ -19,7 +20,13 @@ import { SelectContext, type SelectContextValue } from "./SelectContext";
|
|
|
19
20
|
import { useSelectContext } from "./SelectContext";
|
|
20
21
|
import { SelectItem } from "./SelectItem";
|
|
21
22
|
import { ripple } from "../../../directives/ripple";
|
|
22
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
borderDefault,
|
|
25
|
+
borderSubtle,
|
|
26
|
+
type ComponentSize,
|
|
27
|
+
textMuted,
|
|
28
|
+
textPlaceholder,
|
|
29
|
+
} from "../../../styles/tokens.styles";
|
|
23
30
|
import { createControllableSignal } from "../../../hooks/createControllableSignal";
|
|
24
31
|
import { createSlotSignal } from "../../../hooks/createSlotSignal";
|
|
25
32
|
import { chevronWrapperClass, getTriggerClass } from "../DropdownTrigger.styles";
|
|
@@ -31,6 +38,28 @@ void ripple;
|
|
|
31
38
|
const multiTagClass = clsx("rounded", "bg-base-200 px-1", "dark:bg-base-600");
|
|
32
39
|
const selectedValueClass = clsx("flex-1", "whitespace-nowrap");
|
|
33
40
|
|
|
41
|
+
// 검색 입력 스타일
|
|
42
|
+
const searchInputClass = clsx(
|
|
43
|
+
"w-full",
|
|
44
|
+
"border-b",
|
|
45
|
+
borderSubtle,
|
|
46
|
+
"bg-transparent",
|
|
47
|
+
"px-2 py-1.5",
|
|
48
|
+
"text-sm",
|
|
49
|
+
"outline-none",
|
|
50
|
+
textPlaceholder,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// 전체선택/해제 버튼 영역 스타일
|
|
54
|
+
const selectAllBarClass = clsx("flex gap-2", "border-b", borderSubtle, "px-2 py-1", "text-xs");
|
|
55
|
+
|
|
56
|
+
// 전체선택/해제 버튼 스타일
|
|
57
|
+
const selectAllBtnClass = clsx(
|
|
58
|
+
"text-primary-500",
|
|
59
|
+
"hover:text-primary-600 dark:hover:text-primary-400",
|
|
60
|
+
"cursor-pointer",
|
|
61
|
+
);
|
|
62
|
+
|
|
34
63
|
/**
|
|
35
64
|
* Select 우측 액션 서브 컴포넌트
|
|
36
65
|
*/
|
|
@@ -94,7 +123,7 @@ const SelectItemTemplate = <TArgs extends unknown[]>(props: {
|
|
|
94
123
|
// Props 정의
|
|
95
124
|
|
|
96
125
|
// 공통 Props (value, onValueChange, multiple 제외)
|
|
97
|
-
interface SelectCommonProps {
|
|
126
|
+
interface SelectCommonProps<TValue = unknown> {
|
|
98
127
|
/** 비활성화 */
|
|
99
128
|
disabled?: boolean;
|
|
100
129
|
|
|
@@ -116,6 +145,12 @@ interface SelectCommonProps {
|
|
|
116
145
|
/** touchMode: 포커스 해제 후에만 에러 표시 */
|
|
117
146
|
touchMode?: boolean;
|
|
118
147
|
|
|
148
|
+
/** 검색 텍스트 추출 함수 (설정 시 검색 입력 자동 표시) */
|
|
149
|
+
getSearchText?: (item: TValue) => string;
|
|
150
|
+
|
|
151
|
+
/** 숨김 여부 판별 함수 */
|
|
152
|
+
getIsHidden?: (item: TValue) => boolean;
|
|
153
|
+
|
|
119
154
|
/** 커스텀 class */
|
|
120
155
|
class?: string;
|
|
121
156
|
|
|
@@ -124,7 +159,7 @@ interface SelectCommonProps {
|
|
|
124
159
|
}
|
|
125
160
|
|
|
126
161
|
// 단일 선택 Props
|
|
127
|
-
interface SelectSingleBaseProps<TValue> extends SelectCommonProps {
|
|
162
|
+
interface SelectSingleBaseProps<TValue> extends SelectCommonProps<TValue> {
|
|
128
163
|
/** 다중 선택 모드 */
|
|
129
164
|
multiple?: false;
|
|
130
165
|
|
|
@@ -142,7 +177,7 @@ interface SelectSingleBaseProps<TValue> extends SelectCommonProps {
|
|
|
142
177
|
}
|
|
143
178
|
|
|
144
179
|
// 다중 선택 Props
|
|
145
|
-
interface SelectMultipleBaseProps<TValue> extends SelectCommonProps {
|
|
180
|
+
interface SelectMultipleBaseProps<TValue> extends SelectCommonProps<TValue> {
|
|
146
181
|
/** 다중 선택 모드 */
|
|
147
182
|
multiple: true;
|
|
148
183
|
|
|
@@ -228,40 +263,52 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
228
263
|
"renderValue",
|
|
229
264
|
"validate",
|
|
230
265
|
"touchMode",
|
|
266
|
+
"getSearchText",
|
|
267
|
+
"getIsHidden",
|
|
231
268
|
]);
|
|
232
269
|
|
|
233
270
|
const [open, setOpen] = createSignal(false);
|
|
234
271
|
|
|
272
|
+
// 검색 텍스트 signal
|
|
273
|
+
const [searchText, setSearchText] = createSignal("");
|
|
274
|
+
|
|
275
|
+
// open → false 시 searchText 초기화
|
|
276
|
+
createEffect(() => {
|
|
277
|
+
if (!open()) {
|
|
278
|
+
setSearchText("");
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
235
282
|
// 선택된 값 관리 (controlled/uncontrolled 패턴)
|
|
236
283
|
type ValueType = T | T[] | undefined;
|
|
237
|
-
const [
|
|
284
|
+
const [value, setValue] = createControllableSignal<ValueType>({
|
|
238
285
|
value: () => local.value,
|
|
239
286
|
onChange: () => local.onValueChange as ((v: ValueType) => void) | undefined,
|
|
240
287
|
} as Parameters<typeof createControllableSignal<ValueType>>[0]);
|
|
241
288
|
|
|
242
289
|
// 값이 선택되어 있는지 확인
|
|
243
|
-
const isSelected = (
|
|
244
|
-
const current =
|
|
290
|
+
const isSelected = (itemValue: T): boolean => {
|
|
291
|
+
const current = value();
|
|
245
292
|
if (current === undefined) return false;
|
|
246
293
|
|
|
247
294
|
if (local.multiple) {
|
|
248
|
-
return Array.isArray(current) && current.includes(
|
|
295
|
+
return Array.isArray(current) && current.includes(itemValue);
|
|
249
296
|
}
|
|
250
|
-
return current ===
|
|
297
|
+
return current === itemValue;
|
|
251
298
|
};
|
|
252
299
|
|
|
253
300
|
// 값 토글
|
|
254
|
-
const toggleValue = (
|
|
301
|
+
const toggleValue = (itemValue: T) => {
|
|
255
302
|
if (local.multiple) {
|
|
256
|
-
const current = (
|
|
257
|
-
const idx = current.indexOf(
|
|
303
|
+
const current = (value() as T[] | undefined) ?? [];
|
|
304
|
+
const idx = current.indexOf(itemValue);
|
|
258
305
|
if (idx >= 0) {
|
|
259
|
-
|
|
306
|
+
setValue([...current.slice(0, idx), ...current.slice(idx + 1)] as T[]);
|
|
260
307
|
} else {
|
|
261
|
-
|
|
308
|
+
setValue([...current, itemValue] as T[]);
|
|
262
309
|
}
|
|
263
310
|
} else {
|
|
264
|
-
|
|
311
|
+
setValue(itemValue);
|
|
265
312
|
}
|
|
266
313
|
};
|
|
267
314
|
|
|
@@ -302,7 +349,7 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
302
349
|
|
|
303
350
|
// 유효성 검사 메시지
|
|
304
351
|
const errorMsg = createMemo(() => {
|
|
305
|
-
const v =
|
|
352
|
+
const v = value();
|
|
306
353
|
if (local.required && (v === undefined || v === null || v === ""))
|
|
307
354
|
return "필수 입력 항목입니다";
|
|
308
355
|
return local.validate?.(v);
|
|
@@ -317,6 +364,57 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
317
364
|
class: local.class,
|
|
318
365
|
});
|
|
319
366
|
|
|
367
|
+
// 검색 필터링 (계층 구조 지원)
|
|
368
|
+
const filteredItems = createMemo((): T[] | undefined => {
|
|
369
|
+
if (!local.items) return undefined;
|
|
370
|
+
if (!local.getSearchText || !searchText()) return local.items;
|
|
371
|
+
|
|
372
|
+
const terms = searchText().trim().split(" ").filter(Boolean);
|
|
373
|
+
if (terms.length === 0) return local.items;
|
|
374
|
+
|
|
375
|
+
// 계층 구조에서 자식 매칭 시 부모도 포함
|
|
376
|
+
const matchesSearch = (item: T): boolean => {
|
|
377
|
+
const text = local.getSearchText!(item).toLowerCase();
|
|
378
|
+
if (terms.every((t) => text.includes(t.toLowerCase()))) return true;
|
|
379
|
+
|
|
380
|
+
// 자식 중 매칭되는 항목이 있으면 부모도 표시
|
|
381
|
+
if (local.getChildren) {
|
|
382
|
+
const itemChildren = local.getChildren(item, 0, 0);
|
|
383
|
+
if (itemChildren?.some((child) => matchesSearch(child))) return true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return false;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
return local.items.filter((item) => matchesSearch(item));
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// 숨김 필터링 적용된 items
|
|
393
|
+
const visibleItems = createMemo((): T[] | undefined => {
|
|
394
|
+
const items = filteredItems();
|
|
395
|
+
if (!items || !local.getIsHidden) return items;
|
|
396
|
+
|
|
397
|
+
return items.filter((item) => {
|
|
398
|
+
// 숨김 항목이지만 선택된 경우 표시 (취소선으로)
|
|
399
|
+
if (local.getIsHidden!(item)) {
|
|
400
|
+
return isSelected(item);
|
|
401
|
+
}
|
|
402
|
+
return true;
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// 전체선택
|
|
407
|
+
const handleSelectAll = () => {
|
|
408
|
+
const items = visibleItems();
|
|
409
|
+
if (!items) return;
|
|
410
|
+
setValue(items);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// 전체해제
|
|
414
|
+
const handleDeselectAll = () => {
|
|
415
|
+
setValue([] as unknown as T[]);
|
|
416
|
+
};
|
|
417
|
+
|
|
320
418
|
// 내부 컴포넌트: Provider 안에서 children을 resolve하여 슬롯 등록을 트리거
|
|
321
419
|
const SelectInner: ParentComponent = (innerProps) => {
|
|
322
420
|
// children() resolve로 서브 컴포넌트 등록 트리거 (Header, Action, ItemTemplate은 null 반환)
|
|
@@ -334,39 +432,52 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
334
432
|
const tpl = getItemTemplate();
|
|
335
433
|
return (
|
|
336
434
|
<For each={itemList}>
|
|
337
|
-
{(item, index) =>
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
<
|
|
341
|
-
{(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
435
|
+
{(item, index) => {
|
|
436
|
+
const hidden = () => local.getIsHidden?.(item) ?? false;
|
|
437
|
+
return (
|
|
438
|
+
<SelectItem value={item} class={hidden() ? "line-through opacity-60" : undefined}>
|
|
439
|
+
{tpl ? tpl(item, index(), depth) : String(item)}
|
|
440
|
+
<Show when={local.getChildren?.(item, index(), depth)} keyed>
|
|
441
|
+
{(itemChildren) => {
|
|
442
|
+
// 자식 목록에서 숨김 필터링 적용
|
|
443
|
+
const visibleChildren = () => {
|
|
444
|
+
if (!local.getIsHidden) return itemChildren;
|
|
445
|
+
return itemChildren.filter((child) => {
|
|
446
|
+
if (local.getIsHidden!(child)) return isSelected(child);
|
|
447
|
+
return true;
|
|
448
|
+
});
|
|
449
|
+
};
|
|
450
|
+
return (
|
|
451
|
+
<Show when={visibleChildren().length > 0}>
|
|
452
|
+
<SelectItem.Children>
|
|
453
|
+
{renderItems(visibleChildren(), depth + 1)}
|
|
454
|
+
</SelectItem.Children>
|
|
455
|
+
</Show>
|
|
456
|
+
);
|
|
457
|
+
}}
|
|
458
|
+
</Show>
|
|
459
|
+
</SelectItem>
|
|
460
|
+
);
|
|
461
|
+
}}
|
|
351
462
|
</For>
|
|
352
463
|
);
|
|
353
464
|
};
|
|
354
465
|
|
|
355
466
|
// 선택된 값 렌더링 (items 방식일 때 itemTemplate 재사용)
|
|
356
|
-
const renderValue = (
|
|
467
|
+
const renderValue = (renderVal: T): JSX.Element => {
|
|
357
468
|
if (local.renderValue) {
|
|
358
|
-
return local.renderValue(
|
|
469
|
+
return local.renderValue(renderVal);
|
|
359
470
|
}
|
|
360
471
|
const tpl = getItemTemplate();
|
|
361
472
|
if (tpl) {
|
|
362
|
-
return tpl(
|
|
473
|
+
return tpl(renderVal, 0, 0);
|
|
363
474
|
}
|
|
364
|
-
return <>{String(
|
|
475
|
+
return <>{String(renderVal)}</>;
|
|
365
476
|
};
|
|
366
477
|
|
|
367
478
|
// 선택된 값 표시
|
|
368
479
|
const renderSelectedValue = (): JSX.Element => {
|
|
369
|
-
const current =
|
|
480
|
+
const current = value();
|
|
370
481
|
|
|
371
482
|
if (current === undefined || (Array.isArray(current) && current.length === 0)) {
|
|
372
483
|
return <span class={textMuted}>{local.placeholder ?? ""}</span>;
|
|
@@ -384,6 +495,13 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
384
495
|
return renderValue(current as T);
|
|
385
496
|
};
|
|
386
497
|
|
|
498
|
+
// 미지정 항목 표시 여부: 단일 선택 + required 아님 + items 모드
|
|
499
|
+
const showUnsetItem = () => !local.multiple && !local.required && local.items !== undefined;
|
|
500
|
+
|
|
501
|
+
// 전체선택/해제 버튼 표시 여부: multiple + hideSelectAll 아님 + items 모드
|
|
502
|
+
const showSelectAllBar = () =>
|
|
503
|
+
local.multiple === true && !local.hideSelectAll && local.items !== undefined;
|
|
504
|
+
|
|
387
505
|
return (
|
|
388
506
|
<div {...rest} data-select class={clsx("group", local.inset ? "flex" : "inline-flex")}>
|
|
389
507
|
<Dropdown disabled={local.disabled} open={open()} onOpenChange={setOpen} keyboardNav>
|
|
@@ -415,9 +533,47 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
415
533
|
</Dropdown.Trigger>
|
|
416
534
|
<Dropdown.Content>
|
|
417
535
|
<Show when={header()}>{header()!()}</Show>
|
|
536
|
+
{/* 검색 입력 */}
|
|
537
|
+
<Show when={local.getSearchText && local.items}>
|
|
538
|
+
<input
|
|
539
|
+
type="text"
|
|
540
|
+
data-select-search
|
|
541
|
+
class={searchInputClass}
|
|
542
|
+
placeholder="검색..."
|
|
543
|
+
value={searchText()}
|
|
544
|
+
onInput={(e) => setSearchText(e.currentTarget.value)}
|
|
545
|
+
/>
|
|
546
|
+
</Show>
|
|
547
|
+
{/* 전체선택/해제 버튼 */}
|
|
548
|
+
<Show when={showSelectAllBar()}>
|
|
549
|
+
<div class={selectAllBarClass}>
|
|
550
|
+
<button
|
|
551
|
+
type="button"
|
|
552
|
+
data-select-all
|
|
553
|
+
class={selectAllBtnClass}
|
|
554
|
+
onClick={handleSelectAll}
|
|
555
|
+
>
|
|
556
|
+
전체선택
|
|
557
|
+
</button>
|
|
558
|
+
<button
|
|
559
|
+
type="button"
|
|
560
|
+
data-deselect-all
|
|
561
|
+
class={selectAllBtnClass}
|
|
562
|
+
onClick={handleDeselectAll}
|
|
563
|
+
>
|
|
564
|
+
전체해제
|
|
565
|
+
</button>
|
|
566
|
+
</div>
|
|
567
|
+
</Show>
|
|
418
568
|
<List inset role="listbox">
|
|
419
569
|
<Show when={local.items} fallback={resolved()}>
|
|
420
|
-
{
|
|
570
|
+
{/* 미지정 항목 */}
|
|
571
|
+
<Show when={showUnsetItem()}>
|
|
572
|
+
<SelectItem value={undefined as T}>
|
|
573
|
+
<span class={textMuted}>미지정</span>
|
|
574
|
+
</SelectItem>
|
|
575
|
+
</Show>
|
|
576
|
+
{renderItems(visibleItems() ?? [], 0)}
|
|
421
577
|
</Show>
|
|
422
578
|
</List>
|
|
423
579
|
</Dropdown.Content>
|