@simplysm/solid 13.0.55 → 13.0.56

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.
Files changed (181) hide show
  1. package/README.md +3 -1
  2. package/dist/components/data/crud-detail/CrudDetail.d.ts +14 -0
  3. package/dist/components/data/crud-detail/CrudDetail.d.ts.map +1 -0
  4. package/dist/components/data/crud-detail/CrudDetail.js +348 -0
  5. package/dist/components/data/crud-detail/CrudDetail.js.map +6 -0
  6. package/dist/components/data/crud-detail/CrudDetailAfter.d.ts +7 -0
  7. package/dist/components/data/crud-detail/CrudDetailAfter.d.ts.map +1 -0
  8. package/dist/components/data/crud-detail/CrudDetailAfter.js +14 -0
  9. package/dist/components/data/crud-detail/CrudDetailAfter.js.map +6 -0
  10. package/dist/components/data/crud-detail/CrudDetailBefore.d.ts +7 -0
  11. package/dist/components/data/crud-detail/CrudDetailBefore.d.ts.map +1 -0
  12. package/dist/components/data/crud-detail/CrudDetailBefore.js +14 -0
  13. package/dist/components/data/crud-detail/CrudDetailBefore.js.map +6 -0
  14. package/dist/components/data/crud-detail/CrudDetailTools.d.ts +7 -0
  15. package/dist/components/data/crud-detail/CrudDetailTools.d.ts.map +1 -0
  16. package/dist/components/data/crud-detail/CrudDetailTools.js +14 -0
  17. package/dist/components/data/crud-detail/CrudDetailTools.js.map +6 -0
  18. package/dist/components/data/crud-detail/types.d.ts +45 -0
  19. package/dist/components/data/crud-detail/types.d.ts.map +1 -0
  20. package/dist/components/data/crud-detail/types.js +1 -0
  21. package/dist/components/data/crud-detail/types.js.map +6 -0
  22. package/dist/components/data/crud-sheet/CrudSheet.d.ts +17 -0
  23. package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +1 -0
  24. package/dist/components/data/crud-sheet/CrudSheet.js +679 -0
  25. package/dist/components/data/crud-sheet/CrudSheet.js.map +6 -0
  26. package/dist/components/data/crud-sheet/CrudSheetColumn.d.ts +5 -0
  27. package/dist/components/data/crud-sheet/CrudSheetColumn.d.ts.map +1 -0
  28. package/dist/components/data/crud-sheet/CrudSheetColumn.js +29 -0
  29. package/dist/components/data/crud-sheet/CrudSheetColumn.js.map +6 -0
  30. package/dist/components/data/crud-sheet/CrudSheetFilter.d.ts +7 -0
  31. package/dist/components/data/crud-sheet/CrudSheetFilter.d.ts.map +1 -0
  32. package/dist/components/data/crud-sheet/CrudSheetFilter.js +14 -0
  33. package/dist/components/data/crud-sheet/CrudSheetFilter.js.map +6 -0
  34. package/dist/components/data/crud-sheet/CrudSheetHeader.d.ts +7 -0
  35. package/dist/components/data/crud-sheet/CrudSheetHeader.d.ts.map +1 -0
  36. package/dist/components/data/crud-sheet/CrudSheetHeader.js +14 -0
  37. package/dist/components/data/crud-sheet/CrudSheetHeader.js.map +6 -0
  38. package/dist/components/data/crud-sheet/CrudSheetTools.d.ts +7 -0
  39. package/dist/components/data/crud-sheet/CrudSheetTools.d.ts.map +1 -0
  40. package/dist/components/data/crud-sheet/CrudSheetTools.js +14 -0
  41. package/dist/components/data/crud-sheet/CrudSheetTools.js.map +6 -0
  42. package/dist/components/data/crud-sheet/types.d.ts +109 -0
  43. package/dist/components/data/crud-sheet/types.d.ts.map +1 -0
  44. package/dist/components/data/crud-sheet/types.js +1 -0
  45. package/dist/components/data/crud-sheet/types.js.map +6 -0
  46. package/dist/components/data/kanban/Kanban.d.ts.map +1 -1
  47. package/dist/components/data/kanban/Kanban.js +137 -138
  48. package/dist/components/data/kanban/Kanban.js.map +2 -2
  49. package/dist/components/data/kanban/KanbanContext.d.ts +5 -1
  50. package/dist/components/data/kanban/KanbanContext.d.ts.map +1 -1
  51. package/dist/components/data/kanban/KanbanContext.js.map +1 -1
  52. package/dist/components/data/list/ListItem.d.ts.map +1 -1
  53. package/dist/components/data/list/ListItem.js +109 -99
  54. package/dist/components/data/list/ListItem.js.map +2 -2
  55. package/dist/components/data/sheet/DataSheet.js +1 -1
  56. package/dist/components/data/sheet/DataSheet.js.map +2 -2
  57. package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
  58. package/dist/components/data/sheet/DataSheet.styles.js +1 -1
  59. package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
  60. package/dist/components/disclosure/Dialog.d.ts +16 -10
  61. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  62. package/dist/components/disclosure/Dialog.js +126 -91
  63. package/dist/components/disclosure/Dialog.js.map +2 -2
  64. package/dist/components/disclosure/DialogContext.d.ts +2 -4
  65. package/dist/components/disclosure/DialogContext.d.ts.map +1 -1
  66. package/dist/components/disclosure/DialogContext.js.map +1 -1
  67. package/dist/components/disclosure/DialogProvider.d.ts.map +1 -1
  68. package/dist/components/disclosure/DialogProvider.js +14 -9
  69. package/dist/components/disclosure/DialogProvider.js.map +2 -2
  70. package/dist/components/disclosure/Dropdown.d.ts +46 -22
  71. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  72. package/dist/components/disclosure/Dropdown.js +100 -65
  73. package/dist/components/disclosure/Dropdown.js.map +2 -2
  74. package/dist/components/feedback/notification/NotificationBanner.d.ts.map +1 -1
  75. package/dist/components/feedback/notification/NotificationBanner.js +3 -3
  76. package/dist/components/feedback/notification/NotificationBanner.js.map +1 -1
  77. package/dist/components/feedback/notification/NotificationBell.d.ts.map +1 -1
  78. package/dist/components/feedback/notification/NotificationBell.js +84 -84
  79. package/dist/components/feedback/notification/NotificationBell.js.map +2 -2
  80. package/dist/components/form-control/combobox/Combobox.d.ts +6 -3
  81. package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
  82. package/dist/components/form-control/combobox/Combobox.js +150 -168
  83. package/dist/components/form-control/combobox/Combobox.js.map +2 -2
  84. package/dist/components/form-control/combobox/ComboboxContext.d.ts +3 -0
  85. package/dist/components/form-control/combobox/ComboboxContext.d.ts.map +1 -1
  86. package/dist/components/form-control/combobox/ComboboxContext.js.map +1 -1
  87. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts +0 -2
  88. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts.map +1 -1
  89. package/dist/components/form-control/date-range-picker/DateRangePicker.js +9 -17
  90. package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
  91. package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
  92. package/dist/components/form-control/field/Field.styles.js +2 -1
  93. package/dist/components/form-control/field/Field.styles.js.map +1 -1
  94. package/dist/components/form-control/field/NumberInput.d.ts +15 -5
  95. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  96. package/dist/components/form-control/field/NumberInput.js +181 -141
  97. package/dist/components/form-control/field/NumberInput.js.map +2 -2
  98. package/dist/components/form-control/field/TextInput.d.ts +9 -5
  99. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  100. package/dist/components/form-control/field/TextInput.js +199 -154
  101. package/dist/components/form-control/field/TextInput.js.map +2 -2
  102. package/dist/components/form-control/select/Select.d.ts +3 -3
  103. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  104. package/dist/components/form-control/select/Select.js +116 -100
  105. package/dist/components/form-control/select/Select.js.map +2 -2
  106. package/dist/components/form-control/select/SelectContext.d.ts +9 -1
  107. package/dist/components/form-control/select/SelectContext.d.ts.map +1 -1
  108. package/dist/components/form-control/select/SelectContext.js.map +1 -1
  109. package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
  110. package/dist/components/form-control/select/SelectItem.js +77 -67
  111. package/dist/components/form-control/select/SelectItem.js.map +2 -2
  112. package/dist/components/layout/topbar/TopbarMenu.d.ts.map +1 -1
  113. package/dist/components/layout/topbar/TopbarMenu.js +63 -57
  114. package/dist/components/layout/topbar/TopbarMenu.js.map +2 -2
  115. package/dist/components/layout/topbar/TopbarUser.d.ts.map +1 -1
  116. package/dist/components/layout/topbar/TopbarUser.js +53 -54
  117. package/dist/components/layout/topbar/TopbarUser.js.map +2 -2
  118. package/dist/hooks/createControllableStore.d.ts +29 -0
  119. package/dist/hooks/createControllableStore.d.ts.map +1 -0
  120. package/dist/hooks/createControllableStore.js +19 -0
  121. package/dist/hooks/createControllableStore.js.map +6 -0
  122. package/dist/index.d.ts +5 -1
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +6 -2
  125. package/dist/index.js.map +1 -1
  126. package/dist/styles/patterns.styles.d.ts.map +1 -1
  127. package/dist/styles/patterns.styles.js +7 -1
  128. package/dist/styles/patterns.styles.js.map +1 -1
  129. package/docs/data-components.md +428 -0
  130. package/docs/disclosure.md +65 -35
  131. package/docs/form-controls.md +18 -3
  132. package/docs/helpers.md +0 -39
  133. package/docs/hooks.md +39 -0
  134. package/package.json +4 -3
  135. package/src/components/data/crud-detail/CrudDetail.tsx +346 -0
  136. package/src/components/data/crud-detail/CrudDetailAfter.tsx +19 -0
  137. package/src/components/data/crud-detail/CrudDetailBefore.tsx +19 -0
  138. package/src/components/data/crud-detail/CrudDetailTools.tsx +19 -0
  139. package/src/components/data/crud-detail/types.ts +58 -0
  140. package/src/components/data/crud-sheet/CrudSheet.tsx +628 -0
  141. package/src/components/data/crud-sheet/CrudSheetColumn.tsx +34 -0
  142. package/src/components/data/crud-sheet/CrudSheetFilter.tsx +21 -0
  143. package/src/components/data/crud-sheet/CrudSheetHeader.tsx +19 -0
  144. package/src/components/data/crud-sheet/CrudSheetTools.tsx +21 -0
  145. package/src/components/data/crud-sheet/types.ts +133 -0
  146. package/src/components/data/kanban/Kanban.tsx +72 -65
  147. package/src/components/data/kanban/KanbanContext.ts +7 -1
  148. package/src/components/data/list/ListItem.tsx +31 -18
  149. package/src/components/data/sheet/DataSheet.styles.ts +1 -1
  150. package/src/components/data/sheet/DataSheet.tsx +1 -1
  151. package/src/components/disclosure/Dialog.tsx +143 -105
  152. package/src/components/disclosure/DialogContext.ts +2 -4
  153. package/src/components/disclosure/DialogProvider.tsx +4 -2
  154. package/src/components/disclosure/Dropdown.tsx +174 -86
  155. package/src/components/feedback/notification/NotificationBanner.tsx +3 -9
  156. package/src/components/feedback/notification/NotificationBell.tsx +51 -57
  157. package/src/components/form-control/combobox/Combobox.tsx +109 -134
  158. package/src/components/form-control/combobox/ComboboxContext.ts +4 -1
  159. package/src/components/form-control/date-range-picker/DateRangePicker.tsx +6 -16
  160. package/src/components/form-control/field/Field.styles.ts +1 -0
  161. package/src/components/form-control/field/NumberInput.tsx +131 -88
  162. package/src/components/form-control/field/TextInput.tsx +139 -88
  163. package/src/components/form-control/select/Select.tsx +85 -67
  164. package/src/components/form-control/select/SelectContext.ts +12 -1
  165. package/src/components/form-control/select/SelectItem.tsx +39 -18
  166. package/src/components/layout/topbar/TopbarMenu.tsx +52 -55
  167. package/src/components/layout/topbar/TopbarUser.tsx +28 -31
  168. package/src/hooks/createControllableStore.ts +47 -0
  169. package/src/index.ts +5 -1
  170. package/src/styles/patterns.styles.ts +7 -1
  171. package/tailwind.css +4 -0
  172. package/dist/helpers/splitSlots.d.ts +0 -25
  173. package/dist/helpers/splitSlots.d.ts.map +0 -1
  174. package/dist/helpers/splitSlots.js +0 -25
  175. package/dist/helpers/splitSlots.js.map +0 -6
  176. package/dist/hooks/createItemTemplate.d.ts +0 -17
  177. package/dist/hooks/createItemTemplate.d.ts.map +0 -1
  178. package/dist/hooks/createItemTemplate.js +0 -40
  179. package/dist/hooks/createItemTemplate.js.map +0 -6
  180. package/src/helpers/splitSlots.ts +0 -51
  181. package/src/hooks/createItemTemplate.tsx +0 -42
@@ -1,25 +1,14 @@
1
- import {
2
- children,
3
- createMemo,
4
- createSignal,
5
- For,
6
- type JSX,
7
- onCleanup,
8
- Show,
9
- splitProps,
10
- } from "solid-js";
1
+ import { createMemo, createSignal, For, type JSX, onCleanup, Show, splitProps } from "solid-js";
11
2
  import clsx from "clsx";
12
3
  import { IconChevronDown, IconLoader2 } from "@tabler/icons-solidjs";
13
4
  import { DebounceQueue } from "@simplysm/core-common";
14
5
  import { Icon } from "../../display/Icon";
15
6
  import { Dropdown } from "../../disclosure/Dropdown";
16
7
  import { List } from "../../data/list/List";
17
- import { ComboboxContext, type ComboboxContextValue } from "./ComboboxContext";
8
+ import { ComboboxContext, type ComboboxContextValue, useComboboxContext } from "./ComboboxContext";
18
9
  import { ComboboxItem } from "./ComboboxItem";
19
10
  import { ripple } from "../../../directives/ripple";
20
11
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
21
- import { createItemTemplate } from "../../../hooks/createItemTemplate";
22
- import { splitSlots } from "../../../helpers/splitSlots";
23
12
  import { type ComponentSize, textMuted } from "../../../styles/tokens.styles";
24
13
  import { chevronWrapperClass, getTriggerClass } from "../DropdownTrigger.styles";
25
14
  import { Invalid } from "../Invalid";
@@ -36,8 +25,18 @@ const inputClass = clsx(
36
25
 
37
26
  const noResultsClass = clsx("px-3 py-2", textMuted);
38
27
 
39
- const { TemplateSlot: ComboboxItemTemplate, getTemplate: getComboboxItemTemplate } =
40
- createItemTemplate<[item: unknown, index: number]>("data-combobox-item-template");
28
+ /**
29
+ * 아이템 템플릿 서브 컴포넌트
30
+ */
31
+ const ComboboxItemTemplate = <TArgs extends unknown[]>(props: {
32
+ children: (...args: TArgs) => JSX.Element;
33
+ }) => {
34
+ const ctx = useComboboxContext();
35
+ // eslint-disable-next-line solid/reactivity -- 렌더 함수를 signal에 저장, JSX tracked scope에서 호출됨
36
+ ctx.setItemTemplate(props.children as (...args: unknown[]) => JSX.Element);
37
+ onCleanup(() => ctx.setItemTemplate(undefined));
38
+ return null;
39
+ };
41
40
 
42
41
  // Props 정의
43
42
  export interface ComboboxProps<TValue = unknown> {
@@ -150,8 +149,6 @@ export const Combobox: ComboboxComponent = <T,>(props: ComboboxProps<T>) => {
150
149
  "touchMode",
151
150
  ]);
152
151
 
153
- let triggerRef!: HTMLDivElement;
154
-
155
152
  // 상태
156
153
  const [open, setOpen] = createSignal(false);
157
154
  const [query, setQuery] = createSignal("");
@@ -190,11 +187,19 @@ export const Combobox: ComboboxComponent = <T,>(props: ComboboxProps<T>) => {
190
187
  setOpen(false);
191
188
  };
192
189
 
190
+ // 아이템 템플릿 signal
191
+ const [itemTemplate, _setItemTemplate] = createSignal<
192
+ ((...args: unknown[]) => JSX.Element) | undefined
193
+ >();
194
+ const setItemTemplate = (fn: ((...args: unknown[]) => JSX.Element) | undefined) =>
195
+ _setItemTemplate(() => fn);
196
+
193
197
  // Context 값
194
198
  const contextValue: ComboboxContextValue<T> = {
195
199
  isSelected,
196
200
  selectValue,
197
201
  closeDropdown,
202
+ setItemTemplate,
198
203
  };
199
204
 
200
205
  // 검색 실행
@@ -224,24 +229,11 @@ export const Combobox: ComboboxComponent = <T,>(props: ComboboxProps<T>) => {
224
229
  }
225
230
  };
226
231
 
227
- // 트리거 클릭
228
- const handleTriggerClick = (e: MouseEvent) => {
229
- if (local.disabled) return;
230
-
231
- // input 클릭 시 드롭다운 토글
232
- const target = e.target as HTMLElement;
233
- if (target.tagName === "INPUT") {
234
- if (!open()) {
235
- setOpen(true);
236
- performSearch(query());
237
- }
238
- } else {
239
- // 다른 영역 클릭 시 토글
240
- const wasOpen = open();
241
- setOpen(!wasOpen);
242
- if (!wasOpen) {
243
- performSearch(query());
244
- }
232
+ // Dropdown 열림/닫힘 변경 핸들러
233
+ const handleOpenChange = (isOpen: boolean) => {
234
+ setOpen(isOpen);
235
+ if (isOpen) {
236
+ performSearch(query());
245
237
  }
246
238
  };
247
239
 
@@ -283,123 +275,106 @@ export const Combobox: ComboboxComponent = <T,>(props: ComboboxProps<T>) => {
283
275
  // 참고: 초기 검색은 handleTriggerClick에서 수행됨
284
276
  // 입력 시에는 handleInput에서 performSearch가 호출됨
285
277
 
286
- // 내부 컴포넌트
287
- const ComboboxInner = (innerProps: { children?: JSX.Element }) => {
288
- const resolved = children(() => innerProps.children);
289
- const [slots, childItems] = splitSlots(resolved, ["comboboxItemTemplate"] as const);
290
-
291
- // itemTemplate 함수 추출
292
- const getItemTemplate = (): ((item: T, index: number) => JSX.Element) | undefined => {
293
- return getComboboxItemTemplate(slots().comboboxItemTemplate) as
294
- | ((item: T, index: number) => JSX.Element)
295
- | undefined;
296
- };
297
-
298
- // 선택된 값 또는 입력 표시
299
- const renderDisplayContent = (): JSX.Element => {
300
- const currentValue = getValue();
301
-
302
- // 드롭다운이 열려있거나 값이 없으면 입력 필드 표시
303
- if (open() || currentValue === undefined) {
304
- return (
305
- <input
306
- ref={(el) => {
307
- // 드롭다운이 열릴 때 input에 포커스
308
- if (open()) {
309
- requestAnimationFrame(() => el.focus());
310
- }
311
- }}
312
- type="text"
313
- class={inputClass}
314
- value={query()}
315
- placeholder={currentValue === undefined ? local.placeholder : undefined}
316
- disabled={local.disabled}
317
- autocomplete="one-time-code"
318
- onInput={handleInput}
319
- />
320
- );
321
- }
322
-
323
- // 값이 있고 드롭다운이 닫혀있으면 값 표시
324
- return <div class="truncate">{local.renderValue(currentValue)}</div>;
325
- };
278
+ // 선택된 값 또는 입력 표시
279
+ const renderDisplayContent = (): JSX.Element => {
280
+ const currentValue = getValue();
326
281
 
327
- // 아이템 렌더링
328
- const renderItems = (): JSX.Element => {
329
- const itemTemplate = getItemTemplate();
282
+ // 드롭다운이 열려있거나 값이 없으면 입력 필드 표시
283
+ if (open() || currentValue === undefined) {
284
+ return (
285
+ <input
286
+ ref={(el) => {
287
+ // 드롭다운이 열릴 때 input에 포커스
288
+ if (open()) {
289
+ requestAnimationFrame(() => el.focus());
290
+ }
291
+ }}
292
+ type="text"
293
+ class={inputClass}
294
+ value={query()}
295
+ placeholder={currentValue === undefined ? local.placeholder : undefined}
296
+ disabled={local.disabled}
297
+ autocomplete="one-time-code"
298
+ onInput={handleInput}
299
+ />
300
+ );
301
+ }
330
302
 
331
- // 로딩
332
- if (busyCount() > 0) {
333
- return <div class={noResultsClass}>검색 중...</div>;
334
- }
303
+ // 값이 있고 드롭다운이 닫혀있으면 값 표시
304
+ return <div class="truncate">{local.renderValue(currentValue)}</div>;
305
+ };
335
306
 
336
- // children 방식 (아이템이 직접 전달된 경우)
337
- const resolvedChildren = childItems();
338
- if (resolvedChildren.length > 0) {
339
- return <>{resolvedChildren}</>;
340
- }
307
+ // 아이템 렌더링
308
+ const renderItems = (): JSX.Element => {
309
+ const template = itemTemplate() as ((item: T, index: number) => JSX.Element) | undefined;
341
310
 
342
- // items가 비어있는 경우
343
- if (items().length === 0) {
344
- return <div class={noResultsClass}>검색 결과가 없습니다</div>;
345
- }
311
+ // 로딩
312
+ if (busyCount() > 0) {
313
+ return <div class={noResultsClass}>검색 중...</div>;
314
+ }
346
315
 
347
- // ItemTemplate 방식
348
- if (itemTemplate) {
349
- return (
350
- <For each={items()}>
351
- {(item, index) => (
352
- <ComboboxItem value={item}>{itemTemplate(item, index())}</ComboboxItem>
353
- )}
354
- </For>
355
- );
356
- }
316
+ // items가 비어있는 경우
317
+ if (items().length === 0) {
318
+ return <div class={noResultsClass}>검색 결과가 없습니다</div>;
319
+ }
357
320
 
358
- // 기본 렌더링
321
+ // ItemTemplate 방식
322
+ if (template) {
359
323
  return (
360
324
  <For each={items()}>
361
- {(item) => <ComboboxItem value={item}>{String(item)}</ComboboxItem>}
325
+ {(item, index) => <ComboboxItem value={item}>{template(item, index())}</ComboboxItem>}
362
326
  </For>
363
327
  );
364
- };
328
+ }
365
329
 
330
+ // 기본 렌더링
366
331
  return (
367
- <div {...rest} data-combobox class={local.inset ? "flex" : "inline-flex"}>
368
- <div
369
- ref={triggerRef}
370
- use:ripple={!local.disabled}
371
- role="combobox"
372
- aria-haspopup="listbox"
373
- aria-expanded={open()}
374
- aria-disabled={local.disabled || undefined}
375
- aria-required={local.required || undefined}
376
- tabIndex={local.disabled ? -1 : 0}
377
- class={getTriggerClassName()}
378
- style={local.style}
379
- onClick={handleTriggerClick}
380
- onKeyDown={handleTriggerKeyDown}
381
- >
382
- <div class={selectedValueClass}>{renderDisplayContent()}</div>
383
- <div class={chevronWrapperClass}>
384
- <Show when={busyCount() > 0} fallback={<Icon icon={IconChevronDown} size="1em" />}>
385
- <Icon icon={IconLoader2} size="1em" class="animate-spin" />
386
- </Show>
387
- </div>
388
- </div>
389
-
390
- <Dropdown triggerRef={() => triggerRef} open={open()} onOpenChange={setOpen} keyboardNav>
391
- <List inset role="listbox">
392
- {renderItems()}
393
- </List>
394
- </Dropdown>
395
- </div>
332
+ <For each={items()}>{(item) => <ComboboxItem value={item}>{String(item)}</ComboboxItem>}</For>
396
333
  );
397
334
  };
398
335
 
399
336
  return (
400
337
  <Invalid message={errorMsg()} variant="border" touchMode={local.touchMode}>
401
338
  <ComboboxContext.Provider value={contextValue as ComboboxContextValue}>
402
- <ComboboxInner>{local.children}</ComboboxInner>
339
+ <div {...rest} data-combobox class={local.inset ? "flex" : "inline-flex"}>
340
+ <Dropdown
341
+ disabled={local.disabled}
342
+ open={open()}
343
+ onOpenChange={handleOpenChange}
344
+ keyboardNav
345
+ >
346
+ <Dropdown.Trigger>
347
+ <div
348
+ use:ripple={!local.disabled}
349
+ role="combobox"
350
+ aria-haspopup="listbox"
351
+ aria-expanded={open()}
352
+ aria-disabled={local.disabled || undefined}
353
+ aria-required={local.required || undefined}
354
+ tabIndex={local.disabled ? -1 : 0}
355
+ class={getTriggerClassName()}
356
+ style={local.style}
357
+ onKeyDown={handleTriggerKeyDown}
358
+ >
359
+ <div class={selectedValueClass}>{renderDisplayContent()}</div>
360
+ <div class={chevronWrapperClass}>
361
+ <Show
362
+ when={busyCount() > 0}
363
+ fallback={<Icon icon={IconChevronDown} size="1em" />}
364
+ >
365
+ <Icon icon={IconLoader2} size="1em" class="animate-spin" />
366
+ </Show>
367
+ </div>
368
+ </div>
369
+ </Dropdown.Trigger>
370
+ <Dropdown.Content>
371
+ <List inset role="listbox">
372
+ {local.children}
373
+ {renderItems()}
374
+ </List>
375
+ </Dropdown.Content>
376
+ </Dropdown>
377
+ </div>
403
378
  </ComboboxContext.Provider>
404
379
  </Invalid>
405
380
  );
@@ -1,4 +1,4 @@
1
- import { createContext, useContext } from "solid-js";
1
+ import { type JSX, createContext, useContext } from "solid-js";
2
2
 
3
3
  export interface ComboboxContextValue<TValue = unknown> {
4
4
  /** 값이 선택되어 있는지 확인 */
@@ -9,6 +9,9 @@ export interface ComboboxContextValue<TValue = unknown> {
9
9
 
10
10
  /** 드롭다운 닫기 */
11
11
  closeDropdown: () => void;
12
+
13
+ /** 아이템 템플릿 등록 */
14
+ setItemTemplate: (fn: ((...args: unknown[]) => JSX.Element) | undefined) => void;
12
15
  }
13
16
 
14
17
  export const ComboboxContext = createContext<ComboboxContextValue>();
@@ -39,9 +39,6 @@ export interface DateRangePickerProps {
39
39
  /** 사이즈 */
40
40
  size?: FieldSize;
41
41
 
42
- /** 기간 타입 라벨 (기본값: { day: "일", month: "월", range: "범위" }) */
43
- periodLabels?: Partial<Record<DateRangePeriodType, string>>;
44
-
45
42
  /** 커스텀 class */
46
43
  class?: string;
47
44
 
@@ -90,19 +87,10 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
90
87
  "required",
91
88
  "disabled",
92
89
  "size",
93
- "periodLabels",
94
90
  "class",
95
91
  "style",
96
92
  ]);
97
93
 
98
- // 기간 타입 라벨
99
- const labels = (): Record<DateRangePeriodType, string> => ({
100
- day: "일",
101
- month: "월",
102
- range: "범위",
103
- ...local.periodLabels,
104
- });
105
-
106
94
  // controlled/uncontrolled 패턴
107
95
  const [periodType, setPeriodType] = createControllableSignal({
108
96
  value: () => local.periodType ?? ("range" as DateRangePeriodType),
@@ -170,15 +158,17 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
170
158
  <Select
171
159
  value={periodType()}
172
160
  onValueChange={handlePeriodTypeChange}
173
- renderValue={(v: DateRangePeriodType) => <>{labels()[v]}</>}
161
+ renderValue={(v: DateRangePeriodType) => (
162
+ <>{{ day: "일", month: "월", range: "범위" }[v]}</>
163
+ )}
174
164
  required
175
165
  disabled={local.disabled}
176
166
  size={local.size}
177
167
  inset
178
168
  >
179
- <Select.Item value={"day" as DateRangePeriodType}>{labels().day}</Select.Item>
180
- <Select.Item value={"month" as DateRangePeriodType}>{labels().month}</Select.Item>
181
- <Select.Item value={"range" as DateRangePeriodType}>{labels().range}</Select.Item>
169
+ <Select.Item value={"day" as DateRangePeriodType}>일</Select.Item>
170
+ <Select.Item value={"month" as DateRangePeriodType}>월</Select.Item>
171
+ <Select.Item value={"range" as DateRangePeriodType}>범위</Select.Item>
182
172
  </Select>
183
173
 
184
174
  <Show
@@ -22,6 +22,7 @@ export const fieldBaseClass = clsx(
22
22
  fieldSurface,
23
23
  "px-2 py-1",
24
24
  "h-field",
25
+ "[text-decoration:inherit]",
25
26
  );
26
27
 
27
28
  // 사이즈별 스타일