@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,12 +1,15 @@
1
1
  import {
2
2
  type JSX,
3
3
  type ParentComponent,
4
+ createContext,
4
5
  createEffect,
6
+ createUniqueId,
5
7
  onCleanup,
6
8
  Show,
7
9
  splitProps,
8
10
  For,
9
11
  useContext,
12
+ createSignal,
10
13
  } from "solid-js";
11
14
  import { Portal } from "solid-js/web";
12
15
  import clsx from "clsx";
@@ -21,15 +24,42 @@ import { borderSubtle } from "../../styles/tokens.styles";
21
24
  import { DialogDefaultsContext } from "./DialogContext";
22
25
  import { registerDialog, unregisterDialog, bringToFront } from "./dialogZIndex";
23
26
 
27
+ type SlotAccessor = (() => JSX.Element) | undefined;
28
+
29
+ interface DialogSlotsContextValue {
30
+ setHeader: (content: SlotAccessor) => void;
31
+ setAction: (content: SlotAccessor) => void;
32
+ }
33
+
34
+ const DialogSlotsContext = createContext<DialogSlotsContextValue>();
35
+
36
+ /**
37
+ * 다이얼로그 헤더 서브 컴포넌트
38
+ */
39
+ const DialogHeader: ParentComponent = (props) => {
40
+ const ctx = useContext(DialogSlotsContext)!;
41
+ // eslint-disable-next-line solid/reactivity -- slot accessor: children은 렌더 시점에 lazy 평가됨
42
+ ctx.setHeader(() => props.children);
43
+ onCleanup(() => ctx.setHeader(undefined));
44
+ return null;
45
+ };
46
+
47
+ /**
48
+ * 다이얼로그 액션 서브 컴포넌트
49
+ */
50
+ const DialogAction: ParentComponent = (props) => {
51
+ const ctx = useContext(DialogSlotsContext)!;
52
+ // eslint-disable-next-line solid/reactivity -- slot accessor: children은 렌더 시점에 lazy 평가됨
53
+ ctx.setAction(() => props.children);
54
+ onCleanup(() => ctx.setAction(undefined));
55
+ return null;
56
+ };
57
+
24
58
  export interface DialogProps {
25
59
  /** 모달 열림 상태 */
26
60
  open?: boolean;
27
61
  /** 열림 상태 변경 시 콜백 */
28
62
  onOpenChange?: (open: boolean) => void;
29
- /** 모달 제목 */
30
- title: string;
31
- /** 헤더 숨김 */
32
- hideHeader?: boolean;
33
63
  /** 닫기 버튼 표시 (기본: true) */
34
64
  closable?: boolean;
35
65
  /** 백드롭 클릭으로 닫기 */
@@ -56,16 +86,12 @@ export interface DialogProps {
56
86
  position?: "bottom-right" | "top-right";
57
87
  /** 헤더 스타일 */
58
88
  headerStyle?: JSX.CSSProperties | string;
59
- /** 헤더 액션 영역 */
60
- headerAction?: JSX.Element;
61
89
  /** 닫기 전 확인 함수 */
62
90
  canDeactivate?: () => boolean;
63
91
  /** 닫기 애니메이션 완료 후 콜백 */
64
92
  onCloseComplete?: () => void;
65
93
  /** 추가 CSS 클래스 */
66
94
  class?: string;
67
- /** 자식 요소 */
68
- children: JSX.Element;
69
95
  }
70
96
 
71
97
  type ResizeDirection =
@@ -124,19 +150,23 @@ const resizePositionMap: Record<ResizeDirection, string> = {
124
150
  * const [open, setOpen] = createSignal(false);
125
151
  *
126
152
  * <Button onClick={() => setOpen(true)}>다이얼로그 열기</Button>
127
- * <Dialog open={open()} onOpenChange={setOpen} title="내 다이얼로그">
153
+ * <Dialog open={open()} onOpenChange={setOpen}>
154
+ * <Dialog.Header>내 다이얼로그</Dialog.Header>
128
155
  * <div class="p-4">다이얼로그 내용</div>
129
156
  * </Dialog>
130
157
  * ```
131
158
  */
132
- export const Dialog: ParentComponent<DialogProps> = (props) => {
159
+ interface DialogComponent extends ParentComponent<DialogProps> {
160
+ Header: typeof DialogHeader;
161
+ Action: typeof DialogAction;
162
+ }
163
+
164
+ export const Dialog: DialogComponent = (props) => {
133
165
  const dialogDefaults = useContext(DialogDefaultsContext);
134
166
 
135
167
  const [local] = splitProps(props, [
136
168
  "open",
137
169
  "onOpenChange",
138
- "title",
139
- "hideHeader",
140
170
  "closable",
141
171
  "closeOnBackdrop",
142
172
  "closeOnEscape",
@@ -150,13 +180,20 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
150
180
  "minHeight",
151
181
  "position",
152
182
  "headerStyle",
153
- "headerAction",
154
183
  "canDeactivate",
155
184
  "onCloseComplete",
156
185
  "class",
157
186
  "children",
158
187
  ]);
159
188
 
189
+ const headerId = "dialog-header-" + createUniqueId();
190
+
191
+ const [header, _setHeader] = createSignal<SlotAccessor>();
192
+ const setHeader = (content: SlotAccessor) => _setHeader(() => content);
193
+ const [action, _setAction] = createSignal<SlotAccessor>();
194
+ const setAction = (content: SlotAccessor) => _setAction(() => content);
195
+ const hasHeader = () => header() !== undefined;
196
+
160
197
  const [open, setOpen] = createControllableSignal({
161
198
  value: () => local.open ?? false,
162
199
  onChange: () => local.onOpenChange,
@@ -185,8 +222,8 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
185
222
  // dialog ref
186
223
  let dialogRef: HTMLDivElement | undefined;
187
224
 
188
- // wrapper ref
189
- let wrapperRef: HTMLDivElement | undefined;
225
+ // wrapper ref (signal로 관리하여 Portal ref 타이밍 보장)
226
+ const [wrapperRef, setWrapperRef] = createSignal<HTMLDivElement>();
190
227
 
191
228
  const closeOnEscape = () => local.closeOnEscape ?? dialogDefaults?.().closeOnEscape ?? true;
192
229
  const closeOnBackdrop = () =>
@@ -210,11 +247,10 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
210
247
  // 열릴 때 등록, 닫힐 때 해제
211
248
  createEffect(() => {
212
249
  if (!open()) return;
213
- if (!wrapperRef) return;
214
- registerDialog(wrapperRef);
215
- onCleanup(() => {
216
- if (wrapperRef) unregisterDialog(wrapperRef);
217
- });
250
+ const el = wrapperRef();
251
+ if (!el) return;
252
+ registerDialog(el);
253
+ onCleanup(() => unregisterDialog(el));
218
254
  });
219
255
 
220
256
  // 닫기 시도 (canDeactivate 체크)
@@ -244,21 +280,22 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
244
280
 
245
281
  // z-index 자동 관리
246
282
  const handleDialogFocus = () => {
247
- if (!wrapperRef) return;
248
- bringToFront(wrapperRef);
283
+ const el = wrapperRef();
284
+ if (!el) return;
285
+ bringToFront(el);
249
286
  };
250
287
 
251
288
  // 드래그 이동
252
289
  const handleHeaderPointerDown = (event: PointerEvent) => {
253
290
  // movable 기본값은 true
254
291
  if (local.movable === false) return;
255
- if (!dialogRef || !wrapperRef) return;
292
+ const wrapperEl = wrapperRef();
293
+ if (!dialogRef || !wrapperEl) return;
256
294
  // 닫기 버튼 등 인터랙티브 요소에서 시작된 이벤트는 드래그로 처리하지 않음
257
295
  if ((event.target as HTMLElement).closest("button")) return;
258
296
 
259
297
  const target = event.currentTarget as HTMLElement;
260
298
  const dialogEl = dialogRef;
261
- const wrapperEl = wrapperRef;
262
299
 
263
300
  const startX = event.clientX;
264
301
  const startY = event.clientY;
@@ -445,92 +482,93 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
445
482
  return (
446
483
  <Show when={mounted()}>
447
484
  <Portal>
448
- <div
449
- ref={(el) => {
450
- wrapperRef = el;
451
- }}
452
- data-modal
453
- class={wrapperClass()}
454
- >
455
- {/* 백드롭 */}
456
- <Show when={!local.float}>
457
- <div data-modal-backdrop class={backdropClass()} onClick={handleBackdropClick} />
458
- </Show>
459
-
460
- {/* 다이얼로그 */}
461
- <div
462
- ref={(el) => {
463
- dialogRef = el;
464
- }}
465
- data-modal-dialog
466
- role="dialog"
467
- aria-modal={local.float ? undefined : true}
468
- aria-label={local.title}
469
- tabIndex={0}
470
- class={twMerge(dialogBaseClass(), local.class)}
471
- style={dialogStyle()}
472
- onFocus={handleDialogFocus}
473
- onTransitionEnd={handleTransitionEnd}
474
- >
475
- {/* 헤더 */}
476
- <Show when={!local.hideHeader}>
477
- <div
478
- data-modal-header
479
- class={clsx(headerClass(), "touch-none")}
480
- style={
481
- typeof local.headerStyle === "string"
482
- ? mergeStyles(local.headerStyle)
483
- : local.headerStyle
484
- }
485
- onPointerDown={handleHeaderPointerDown}
486
- >
487
- <h5 class={clsx("flex-1", "px-4 py-2", "text-sm font-bold")}>{local.title}</h5>
488
- {local.headerAction}
489
- <Show when={local.closable ?? true}>
490
- <button
491
- data-modal-close
492
- type="button"
493
- class={clsx(
494
- "inline-flex items-center justify-center",
495
- "px-3 py-2",
496
- "text-base-400 dark:text-base-500",
497
- "hover:text-base-600 dark:hover:text-base-300",
498
- "cursor-pointer",
499
- "transition-colors",
500
- )}
501
- onClick={handleCloseClick}
502
- >
503
- <Icon icon={IconX} size="1.25em" />
504
- </button>
505
- </Show>
506
- </div>
485
+ <DialogSlotsContext.Provider value={{ setHeader, setAction }}>
486
+ <div ref={setWrapperRef} data-modal class={wrapperClass()}>
487
+ {/* 백드롭 */}
488
+ <Show when={!local.float}>
489
+ <div data-modal-backdrop class={backdropClass()} onClick={handleBackdropClick} />
507
490
  </Show>
508
491
 
509
- {/* 콘텐츠 */}
510
- <div data-modal-content class={dialogContentClass}>
511
- {local.children}
512
- </div>
492
+ {/* 다이얼로그 */}
493
+ <div
494
+ ref={(el) => {
495
+ dialogRef = el;
496
+ }}
497
+ data-modal-dialog
498
+ role="dialog"
499
+ aria-modal={local.float ? undefined : true}
500
+ aria-labelledby={hasHeader() ? headerId : undefined}
501
+ tabIndex={0}
502
+ class={twMerge(dialogBaseClass(), local.class)}
503
+ style={dialogStyle()}
504
+ onFocus={handleDialogFocus}
505
+ onTransitionEnd={handleTransitionEnd}
506
+ >
507
+ {/* 헤더 */}
508
+ <Show when={hasHeader()}>
509
+ <div
510
+ data-modal-header
511
+ class={clsx(headerClass(), "touch-none")}
512
+ style={
513
+ typeof local.headerStyle === "string"
514
+ ? mergeStyles(local.headerStyle)
515
+ : local.headerStyle
516
+ }
517
+ onPointerDown={handleHeaderPointerDown}
518
+ >
519
+ <h5 id={headerId} class={clsx("flex-1", "px-4 py-2", "text-sm font-bold")}>
520
+ {header()!()}
521
+ </h5>
522
+ <Show when={action()}>{action()!()}</Show>
523
+ <Show when={local.closable ?? true}>
524
+ <button
525
+ data-modal-close
526
+ type="button"
527
+ class={clsx(
528
+ "inline-flex items-center justify-center",
529
+ "px-3 py-2",
530
+ "text-base-400 dark:text-base-500",
531
+ "hover:text-base-600 dark:hover:text-base-300",
532
+ "cursor-pointer",
533
+ "transition-colors",
534
+ )}
535
+ onClick={handleCloseClick}
536
+ >
537
+ <Icon icon={IconX} size="1.25em" />
538
+ </button>
539
+ </Show>
540
+ </div>
541
+ </Show>
542
+
543
+ {/* 콘텐츠 */}
544
+ <div data-modal-content class={dialogContentClass}>
545
+ {local.children}
546
+ </div>
513
547
 
514
- {/* 리사이즈 바 */}
515
- <Show when={local.resizable}>
516
- <For each={RESIZE_DIRECTIONS}>
517
- {(direction) => (
518
- <div
519
- data-resize-bar={direction}
520
- class={clsx(
521
- "absolute",
522
- "touch-none",
523
- resizePositionMap[direction],
524
- resizeCursorMap[direction],
525
- )}
526
- onPointerDown={(e) => handleResizeBarPointerDown(e, direction)}
527
- />
528
- )}
529
- </For>
530
- </Show>
548
+ {/* 리사이즈 바 */}
549
+ <Show when={local.resizable}>
550
+ <For each={RESIZE_DIRECTIONS}>
551
+ {(direction) => (
552
+ <div
553
+ data-resize-bar={direction}
554
+ class={clsx(
555
+ "absolute",
556
+ "touch-none",
557
+ resizePositionMap[direction],
558
+ resizeCursorMap[direction],
559
+ )}
560
+ onPointerDown={(e) => handleResizeBarPointerDown(e, direction)}
561
+ />
562
+ )}
563
+ </For>
564
+ </Show>
565
+ </div>
531
566
  </div>
532
- </div>
567
+ </DialogSlotsContext.Provider>
533
568
  </Portal>
534
569
  </Show>
535
570
  );
536
571
  };
572
+
573
+ Dialog.Header = DialogHeader;
574
+ Dialog.Action = DialogAction;
@@ -13,10 +13,8 @@ export const DialogDefaultsContext = createContext<Accessor<DialogDefaults>>();
13
13
 
14
14
  /** 프로그래매틱 다이얼로그 옵션 */
15
15
  export interface DialogShowOptions {
16
- /** 다이얼로그 제목 */
17
- title: string;
18
- /** 헤더 숨김 */
19
- hideHeader?: boolean;
16
+ /** 다이얼로그 헤더 */
17
+ header?: JSX.Element;
20
18
  /** 닫기 버튼 표시 */
21
19
  closable?: boolean;
22
20
  /** 백드롭 클릭으로 닫기 */
@@ -3,6 +3,7 @@ import {
3
3
  type ParentComponent,
4
4
  createSignal,
5
5
  For,
6
+ Show,
6
7
  splitProps,
7
8
  type JSX,
8
9
  } from "solid-js";
@@ -115,8 +116,6 @@ export const DialogProvider: ParentComponent<DialogProviderProps> = (props) => {
115
116
  }
116
117
  }}
117
118
  onCloseComplete={() => removeEntry(entry.id)}
118
- title={entry.options.title}
119
- hideHeader={entry.options.hideHeader}
120
119
  closable={entry.options.closable}
121
120
  closeOnBackdrop={entry.options.closeOnBackdrop}
122
121
  closeOnEscape={entry.options.closeOnEscape}
@@ -132,6 +131,9 @@ export const DialogProvider: ParentComponent<DialogProviderProps> = (props) => {
132
131
  headerStyle={entry.options.headerStyle}
133
132
  canDeactivate={entry.options.canDeactivate}
134
133
  >
134
+ <Show when={entry.options.header !== undefined}>
135
+ <Dialog.Header>{entry.options.header}</Dialog.Header>
136
+ </Show>
135
137
  <DialogInstanceContext.Provider value={instance}>
136
138
  {entry.factory()}
137
139
  </DialogInstanceContext.Provider>