@simplysm/solid 13.0.29 → 13.0.31

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 (220) hide show
  1. package/README.md +10 -5
  2. package/dist/components/data/Pagination.d.ts +4 -5
  3. package/dist/components/data/Pagination.d.ts.map +1 -1
  4. package/dist/components/data/Pagination.js +14 -14
  5. package/dist/components/data/Pagination.js.map +2 -2
  6. package/dist/components/data/Table.js +1 -1
  7. package/dist/components/data/calendar/Calendar.js +1 -1
  8. package/dist/components/data/kanban/Kanban.d.ts +9 -9
  9. package/dist/components/data/kanban/Kanban.d.ts.map +1 -1
  10. package/dist/components/data/kanban/Kanban.js +4 -4
  11. package/dist/components/data/kanban/Kanban.js.map +2 -2
  12. package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
  13. package/dist/components/data/sheet/DataSheet.js +102 -107
  14. package/dist/components/data/sheet/DataSheet.js.map +2 -2
  15. package/dist/components/data/sheet/DataSheet.styles.js +1 -1
  16. package/dist/components/data/sheet/types.d.ts +2 -2
  17. package/dist/components/data/sheet/types.d.ts.map +1 -1
  18. package/dist/components/disclosure/Dialog.d.ts +8 -8
  19. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  20. package/dist/components/disclosure/Dialog.js +64 -69
  21. package/dist/components/disclosure/Dialog.js.map +2 -2
  22. package/dist/components/disclosure/DialogContext.d.ts +4 -4
  23. package/dist/components/disclosure/DialogContext.d.ts.map +1 -1
  24. package/dist/components/disclosure/DialogProvider.js +8 -8
  25. package/dist/components/disclosure/DialogProvider.js.map +2 -2
  26. package/dist/components/feedback/Progress.d.ts +3 -3
  27. package/dist/components/feedback/Progress.d.ts.map +1 -1
  28. package/dist/components/feedback/Progress.js +1 -1
  29. package/dist/components/feedback/Progress.js.map +2 -2
  30. package/dist/components/feedback/busy/BusyContainer.d.ts +1 -0
  31. package/dist/components/feedback/busy/BusyContainer.d.ts.map +1 -1
  32. package/dist/components/feedback/busy/BusyContainer.js +13 -6
  33. package/dist/components/feedback/busy/BusyContainer.js.map +2 -2
  34. package/dist/components/feedback/notification/NotificationBanner.js +1 -1
  35. package/dist/components/feedback/notification/NotificationBanner.js.map +1 -1
  36. package/dist/components/feedback/notification/NotificationBell.d.ts.map +1 -1
  37. package/dist/components/feedback/notification/NotificationBell.js +4 -2
  38. package/dist/components/feedback/notification/NotificationBell.js.map +2 -2
  39. package/dist/components/feedback/notification/NotificationProvider.d.ts.map +1 -1
  40. package/dist/components/feedback/notification/NotificationProvider.js +1 -0
  41. package/dist/components/feedback/notification/NotificationProvider.js.map +1 -1
  42. package/dist/components/form-control/Invalid.d.ts +4 -2
  43. package/dist/components/form-control/Invalid.d.ts.map +1 -1
  44. package/dist/components/form-control/Invalid.js +81 -41
  45. package/dist/components/form-control/Invalid.js.map +2 -2
  46. package/dist/components/form-control/ThemeToggle.d.ts.map +1 -1
  47. package/dist/components/form-control/ThemeToggle.js +4 -5
  48. package/dist/components/form-control/ThemeToggle.js.map +2 -2
  49. package/dist/components/form-control/checkbox/Checkbox.d.ts +4 -2
  50. package/dist/components/form-control/checkbox/Checkbox.d.ts.map +1 -1
  51. package/dist/components/form-control/checkbox/Checkbox.js +65 -52
  52. package/dist/components/form-control/checkbox/Checkbox.js.map +2 -2
  53. package/dist/components/form-control/checkbox/Checkbox.styles.d.ts +1 -2
  54. package/dist/components/form-control/checkbox/Checkbox.styles.d.ts.map +1 -1
  55. package/dist/components/form-control/checkbox/Checkbox.styles.js +3 -9
  56. package/dist/components/form-control/checkbox/Checkbox.styles.js.map +1 -1
  57. package/dist/components/form-control/checkbox/CheckboxGroup.d.ts +9 -9
  58. package/dist/components/form-control/checkbox/CheckboxGroup.d.ts.map +1 -1
  59. package/dist/components/form-control/checkbox/CheckboxGroup.js +10 -82
  60. package/dist/components/form-control/checkbox/CheckboxGroup.js.map +2 -2
  61. package/dist/components/form-control/checkbox/Radio.d.ts +4 -2
  62. package/dist/components/form-control/checkbox/Radio.d.ts.map +1 -1
  63. package/dist/components/form-control/checkbox/Radio.js +64 -51
  64. package/dist/components/form-control/checkbox/Radio.js.map +2 -2
  65. package/dist/components/form-control/checkbox/RadioGroup.d.ts +9 -9
  66. package/dist/components/form-control/checkbox/RadioGroup.d.ts.map +1 -1
  67. package/dist/components/form-control/checkbox/RadioGroup.js +10 -77
  68. package/dist/components/form-control/checkbox/RadioGroup.js.map +2 -2
  69. package/dist/components/form-control/color-picker/ColorPicker.d.ts +8 -3
  70. package/dist/components/form-control/color-picker/ColorPicker.d.ts.map +1 -1
  71. package/dist/components/form-control/color-picker/ColorPicker.js +43 -26
  72. package/dist/components/form-control/color-picker/ColorPicker.js.map +2 -2
  73. package/dist/components/form-control/combobox/Combobox.d.ts +8 -8
  74. package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
  75. package/dist/components/form-control/combobox/Combobox.js +72 -59
  76. package/dist/components/form-control/combobox/Combobox.js.map +2 -2
  77. package/dist/components/form-control/editor/EditorToolbar.d.ts.map +1 -1
  78. package/dist/components/form-control/editor/EditorToolbar.js +3 -2
  79. package/dist/components/form-control/editor/EditorToolbar.js.map +2 -2
  80. package/dist/components/form-control/field/DatePicker.d.ts +6 -0
  81. package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
  82. package/dist/components/form-control/field/DatePicker.js +138 -117
  83. package/dist/components/form-control/field/DatePicker.js.map +2 -2
  84. package/dist/components/form-control/field/DateTimePicker.d.ts +6 -0
  85. package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
  86. package/dist/components/form-control/field/DateTimePicker.js +138 -115
  87. package/dist/components/form-control/field/DateTimePicker.js.map +2 -2
  88. package/dist/components/form-control/field/Field.styles.d.ts +14 -0
  89. package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
  90. package/dist/components/form-control/field/Field.styles.js +30 -0
  91. package/dist/components/form-control/field/Field.styles.js.map +1 -1
  92. package/dist/components/form-control/field/FieldPlaceholder.d.ts +7 -0
  93. package/dist/components/form-control/field/FieldPlaceholder.d.ts.map +1 -0
  94. package/dist/components/form-control/field/FieldPlaceholder.js +34 -0
  95. package/dist/components/form-control/field/FieldPlaceholder.js.map +6 -0
  96. package/dist/components/form-control/field/NumberInput.d.ts +10 -0
  97. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  98. package/dist/components/form-control/field/NumberInput.js +149 -115
  99. package/dist/components/form-control/field/NumberInput.js.map +2 -2
  100. package/dist/components/form-control/field/TextInput.d.ts +12 -0
  101. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  102. package/dist/components/form-control/field/TextInput.js +162 -116
  103. package/dist/components/form-control/field/TextInput.js.map +2 -2
  104. package/dist/components/form-control/field/Textarea.d.ts +10 -0
  105. package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
  106. package/dist/components/form-control/field/Textarea.js +156 -121
  107. package/dist/components/form-control/field/Textarea.js.map +2 -2
  108. package/dist/components/form-control/field/TimePicker.d.ts +10 -0
  109. package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
  110. package/dist/components/form-control/field/TimePicker.js +126 -94
  111. package/dist/components/form-control/field/TimePicker.js.map +2 -2
  112. package/dist/components/form-control/select/Select.d.ts +7 -9
  113. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  114. package/dist/components/form-control/select/Select.js +71 -60
  115. package/dist/components/form-control/select/Select.js.map +2 -2
  116. package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
  117. package/dist/components/form-control/state-preset/StatePreset.js +2 -1
  118. package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
  119. package/dist/components/layout/sidebar/SidebarMenu.js +1 -1
  120. package/dist/components/layout/sidebar/SidebarMenu.js.map +1 -1
  121. package/dist/components/layout/sidebar/SidebarUser.js +2 -2
  122. package/dist/components/layout/sidebar/SidebarUser.js.map +1 -1
  123. package/dist/hooks/createItemTemplate.d.ts +17 -0
  124. package/dist/hooks/createItemTemplate.d.ts.map +1 -0
  125. package/dist/hooks/createItemTemplate.js +40 -0
  126. package/dist/hooks/createItemTemplate.js.map +6 -0
  127. package/dist/hooks/createPointerDrag.d.ts +13 -0
  128. package/dist/hooks/createPointerDrag.d.ts.map +1 -0
  129. package/dist/hooks/createPointerDrag.js +15 -0
  130. package/dist/hooks/createPointerDrag.js.map +6 -0
  131. package/dist/hooks/createSelectionGroup.d.ts +70 -0
  132. package/dist/hooks/createSelectionGroup.d.ts.map +1 -0
  133. package/dist/hooks/createSelectionGroup.js +141 -0
  134. package/dist/hooks/createSelectionGroup.js.map +6 -0
  135. package/dist/hooks/useLocalStorage.d.ts +5 -3
  136. package/dist/hooks/useLocalStorage.d.ts.map +1 -1
  137. package/dist/hooks/useLocalStorage.js.map +1 -1
  138. package/dist/hooks/{createPwaUpdate.d.ts → usePwaUpdate.d.ts} +2 -2
  139. package/dist/hooks/usePwaUpdate.d.ts.map +1 -0
  140. package/dist/hooks/{createPwaUpdate.js → usePwaUpdate.js} +3 -3
  141. package/dist/hooks/usePwaUpdate.js.map +6 -0
  142. package/dist/hooks/useSyncConfig.d.ts +3 -3
  143. package/dist/hooks/useSyncConfig.d.ts.map +1 -1
  144. package/dist/hooks/useSyncConfig.js +6 -7
  145. package/dist/hooks/useSyncConfig.js.map +1 -1
  146. package/dist/index.d.ts +1 -3
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.js +2 -4
  149. package/dist/index.js.map +1 -1
  150. package/dist/providers/InitializeProvider.js +2 -2
  151. package/dist/providers/InitializeProvider.js.map +2 -2
  152. package/dist/providers/ThemeContext.d.ts.map +1 -1
  153. package/dist/providers/ThemeContext.js +2 -1
  154. package/dist/providers/ThemeContext.js.map +2 -2
  155. package/dist/styles/patterns.styles.d.ts +1 -0
  156. package/dist/styles/patterns.styles.d.ts.map +1 -1
  157. package/dist/styles/patterns.styles.js +11 -0
  158. package/dist/styles/patterns.styles.js.map +1 -1
  159. package/dist/styles/tokens.styles.d.ts +1 -0
  160. package/dist/styles/tokens.styles.d.ts.map +1 -1
  161. package/dist/styles/tokens.styles.js.map +1 -1
  162. package/docs/data-components.md +34 -5
  163. package/docs/disclosure.md +28 -8
  164. package/docs/feedback.md +25 -2
  165. package/docs/form-controls.md +289 -33
  166. package/docs/hooks.md +19 -7
  167. package/docs/layout.md +12 -0
  168. package/docs/providers.md +120 -8
  169. package/docs/styling.md +90 -0
  170. package/package.json +3 -3
  171. package/src/components/data/Pagination.tsx +20 -21
  172. package/src/components/data/Table.tsx +1 -1
  173. package/src/components/data/calendar/Calendar.tsx +1 -1
  174. package/src/components/data/kanban/Kanban.tsx +18 -25
  175. package/src/components/data/sheet/DataSheet.styles.ts +1 -1
  176. package/src/components/data/sheet/DataSheet.tsx +122 -131
  177. package/src/components/data/sheet/types.ts +2 -2
  178. package/src/components/disclosure/Dialog.tsx +87 -100
  179. package/src/components/disclosure/DialogContext.ts +4 -4
  180. package/src/components/disclosure/DialogProvider.tsx +4 -4
  181. package/src/components/feedback/Progress.tsx +9 -5
  182. package/src/components/feedback/busy/BusyContainer.tsx +9 -5
  183. package/src/components/feedback/notification/NotificationBanner.tsx +1 -1
  184. package/src/components/feedback/notification/NotificationBell.tsx +4 -12
  185. package/src/components/feedback/notification/NotificationProvider.tsx +1 -0
  186. package/src/components/form-control/Invalid.tsx +114 -52
  187. package/src/components/form-control/ThemeToggle.tsx +4 -17
  188. package/src/components/form-control/checkbox/Checkbox.styles.ts +2 -9
  189. package/src/components/form-control/checkbox/Checkbox.tsx +39 -28
  190. package/src/components/form-control/checkbox/CheckboxGroup.tsx +18 -97
  191. package/src/components/form-control/checkbox/Radio.tsx +39 -28
  192. package/src/components/form-control/checkbox/RadioGroup.tsx +18 -92
  193. package/src/components/form-control/color-picker/ColorPicker.tsx +36 -16
  194. package/src/components/form-control/combobox/Combobox.tsx +43 -33
  195. package/src/components/form-control/editor/EditorToolbar.tsx +3 -14
  196. package/src/components/form-control/field/DatePicker.tsx +99 -97
  197. package/src/components/form-control/field/DateTimePicker.tsx +107 -95
  198. package/src/components/form-control/field/Field.styles.ts +45 -0
  199. package/src/components/form-control/field/FieldPlaceholder.tsx +18 -0
  200. package/src/components/form-control/field/NumberInput.tsx +122 -94
  201. package/src/components/form-control/field/TextInput.tsx +119 -95
  202. package/src/components/form-control/field/Textarea.tsx +124 -98
  203. package/src/components/form-control/field/TimePicker.tsx +101 -75
  204. package/src/components/form-control/select/Select.tsx +52 -44
  205. package/src/components/form-control/state-preset/StatePreset.tsx +2 -8
  206. package/src/components/layout/sidebar/SidebarMenu.tsx +1 -1
  207. package/src/components/layout/sidebar/SidebarUser.tsx +3 -3
  208. package/src/hooks/createItemTemplate.tsx +42 -0
  209. package/src/hooks/createPointerDrag.ts +28 -0
  210. package/src/hooks/createSelectionGroup.tsx +235 -0
  211. package/src/hooks/useLocalStorage.ts +8 -4
  212. package/src/hooks/{createPwaUpdate.ts → usePwaUpdate.ts} +1 -1
  213. package/src/hooks/useSyncConfig.ts +9 -13
  214. package/src/index.ts +1 -3
  215. package/src/providers/InitializeProvider.tsx +2 -2
  216. package/src/providers/ThemeContext.tsx +2 -1
  217. package/src/styles/patterns.styles.ts +12 -0
  218. package/src/styles/tokens.styles.ts +1 -0
  219. package/dist/hooks/createPwaUpdate.d.ts.map +0 -1
  220. package/dist/hooks/createPwaUpdate.js.map +0 -6
@@ -33,6 +33,7 @@ import type {
33
33
  import { isDataSheetColumnDef, DataSheetColumn } from "./DataSheetColumn";
34
34
  import { applySorting, buildHeaderTable, collectAllExpandable, flattenTree } from "./sheetUtils";
35
35
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
36
+ import { createPointerDrag } from "../../../hooks/createPointerDrag";
36
37
  import { Icon } from "../../display/Icon";
37
38
  import { Checkbox } from "../../form-control/checkbox/Checkbox";
38
39
  import { Pagination } from "../Pagination";
@@ -89,8 +90,8 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
89
90
  "sorts",
90
91
  "onSortsChange",
91
92
  "autoSort",
92
- "pageIndex",
93
- "onPageIndexChange",
93
+ "page",
94
+ "onPageChange",
94
95
  "totalPageCount",
95
96
  "itemsPerPage",
96
97
  "displayPageCount",
@@ -245,8 +246,8 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
245
246
 
246
247
  // #region Paging
247
248
  const [currentPage, setCurrentPage] = createControllableSignal({
248
- value: () => local.pageIndex ?? 0,
249
- onChange: () => local.onPageIndexChange,
249
+ value: () => local.page ?? 1,
250
+ onChange: () => local.onPageChange,
250
251
  });
251
252
 
252
253
  const effectivePageCount = createMemo(() => {
@@ -263,7 +264,7 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
263
264
  if ((local.items ?? []).length <= 0) return sortedItems();
264
265
 
265
266
  const page = currentPage();
266
- return sortedItems().slice(page * ipp, (page + 1) * ipp);
267
+ return sortedItems().slice((page - 1) * ipp, page * ipp);
267
268
  });
268
269
 
269
270
  // #region Feature Column Setup (확장/선택 기능 컬럼 공통)
@@ -367,7 +368,6 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
367
368
  function onResizerPointerdown(event: PointerEvent, colKey: string): void {
368
369
  event.preventDefault();
369
370
  const target = event.target as HTMLElement;
370
- target.setPointerCapture(event.pointerId);
371
371
 
372
372
  const th = target.closest("th")!;
373
373
  const container = th
@@ -385,32 +385,28 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
385
385
  height: `${container.scrollHeight}px`,
386
386
  });
387
387
 
388
- const onPointerMove = (e: PointerEvent) => {
389
- const delta = e.clientX - startX;
390
- const newWidth = Math.max(30, startWidth + delta);
391
- const currentRect = container.getBoundingClientRect();
392
- setResizeIndicatorStyle({
393
- display: "block",
394
- left: `${th.getBoundingClientRect().left - currentRect.left + container.scrollLeft + newWidth}px`,
395
- top: "0",
396
- height: `${container.scrollHeight}px`,
397
- });
398
- };
399
-
400
- const onPointerUp = (e: PointerEvent) => {
401
- const delta = e.clientX - startX;
402
- // 실제 드래그가 발생한 경우에만 너비 저장 (더블클릭 시 DOM 재생성으로 dblclick 유실 방지)
403
- if (delta !== 0) {
388
+ createPointerDrag(target, event.pointerId, {
389
+ onMove(e) {
390
+ const delta = e.clientX - startX;
404
391
  const newWidth = Math.max(30, startWidth + delta);
405
- saveColumnWidth(colKey, `${newWidth}px`);
406
- }
407
- setResizeIndicatorStyle({ display: "none" });
408
- target.removeEventListener("pointermove", onPointerMove);
409
- target.removeEventListener("pointerup", onPointerUp);
410
- };
411
-
412
- target.addEventListener("pointermove", onPointerMove);
413
- target.addEventListener("pointerup", onPointerUp);
392
+ const currentRect = container.getBoundingClientRect();
393
+ setResizeIndicatorStyle({
394
+ display: "block",
395
+ left: `${th.getBoundingClientRect().left - currentRect.left + container.scrollLeft + newWidth}px`,
396
+ top: "0",
397
+ height: `${container.scrollHeight}px`,
398
+ });
399
+ },
400
+ onEnd(e) {
401
+ const delta = e.clientX - startX;
402
+ // 실제 드래그가 발생한 경우에만 너비 저장 (더블클릭 시 DOM 재생성으로 dblclick 유실 방지)
403
+ if (delta !== 0) {
404
+ const newWidth = Math.max(30, startWidth + delta);
405
+ saveColumnWidth(colKey, `${newWidth}px`);
406
+ }
407
+ setResizeIndicatorStyle({ display: "none" });
408
+ },
409
+ });
414
410
  }
415
411
 
416
412
  function onResizerDoubleClick(colKey: string): void {
@@ -567,7 +563,6 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
567
563
  function onReorderPointerDown(e: PointerEvent, item: T): void {
568
564
  e.preventDefault();
569
565
  const target = e.currentTarget as HTMLElement;
570
- target.setPointerCapture(e.pointerId);
571
566
 
572
567
  const tableEl = target.closest("table")!;
573
568
  const tbody = tableEl.querySelector("tbody")!;
@@ -575,114 +570,110 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
575
570
 
576
571
  setDragState({ draggingItem: item, targetItem: null, position: null });
577
572
 
578
- const onPointerMove = (ev: PointerEvent) => {
579
- let foundTarget: T | null = null;
580
- let foundPosition: "before" | "after" | "inside" | null = null;
581
-
582
- for (let i = 0; i < rows.length; i++) {
583
- const row = rows[i];
584
- const rect = row.getBoundingClientRect();
585
- if (ev.clientY < rect.top || ev.clientY > rect.bottom) continue;
586
-
587
- if (i >= displayItems().length) break;
588
- const flat = displayItems()[i];
589
- if (flat.item === item) break;
590
-
591
- // 자기 자신의 하위 항목으로는 드롭 불가
592
- if (isDescendant(item, flat.item)) break;
593
-
594
- const relY = ev.clientY - rect.top;
595
- const third = rect.height / 3;
596
-
597
- if (relY < third) {
598
- foundPosition = "before";
599
- } else if (relY > third * 2) {
600
- foundPosition = "after";
601
- } else {
602
- foundPosition = local.getChildren
603
- ? "inside"
604
- : relY < rect.height / 2
605
- ? "before"
606
- : "after";
607
- }
608
- foundTarget = flat.item;
609
- break;
610
- }
611
-
612
- setDragState({ draggingItem: item, targetItem: foundTarget, position: foundPosition });
573
+ createPointerDrag(target, e.pointerId, {
574
+ onMove(ev) {
575
+ let foundTarget: T | null = null;
576
+ let foundPosition: "before" | "after" | "inside" | null = null;
613
577
 
614
- // 인디케이터 DOM 업데이트
615
- for (let i = 0; i < rows.length; i++) {
616
- rows[i].removeAttribute("data-dragging");
617
- rows[i].removeAttribute("data-drag-over");
578
+ for (let i = 0; i < rows.length; i++) {
579
+ const row = rows[i];
580
+ const rect = row.getBoundingClientRect();
581
+ if (ev.clientY < rect.top || ev.clientY > rect.bottom) continue;
618
582
 
619
- if (i < displayItems().length) {
583
+ if (i >= displayItems().length) break;
620
584
  const flat = displayItems()[i];
621
- if (flat.item === item) {
622
- rows[i].setAttribute("data-dragging", "");
623
- }
624
- if (flat.item === foundTarget && foundPosition === "inside") {
625
- rows[i].setAttribute("data-drag-over", "inside");
585
+ if (flat.item === item) break;
586
+
587
+ // 자기 자신의 하위 항목으로는 드롭 불가
588
+ if (isDescendant(item, flat.item)) break;
589
+
590
+ const relY = ev.clientY - rect.top;
591
+ const third = rect.height / 3;
592
+
593
+ if (relY < third) {
594
+ foundPosition = "before";
595
+ } else if (relY > third * 2) {
596
+ foundPosition = "after";
597
+ } else {
598
+ foundPosition = local.getChildren
599
+ ? "inside"
600
+ : relY < rect.height / 2
601
+ ? "before"
602
+ : "after";
626
603
  }
604
+ foundTarget = flat.item;
605
+ break;
627
606
  }
628
- }
629
607
 
630
- // before/after 인디케이터
631
- const indicatorEl = tableEl
632
- .closest("[data-sheet-scroll]")
633
- ?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
634
- if (indicatorEl) {
635
- if (foundTarget != null && foundPosition != null && foundPosition !== "inside") {
636
- const targetIdx = displayItems().findIndex((f) => f.item === foundTarget);
637
- if (targetIdx >= 0) {
638
- const targetRow = rows[targetIdx];
639
- const containerRect = tableEl.closest("[data-sheet-scroll]")!.getBoundingClientRect();
640
- const rowRect = targetRow.getBoundingClientRect();
641
- const scrollEl = tableEl.closest("[data-sheet-scroll]") as HTMLElement;
642
-
643
- const top =
644
- foundPosition === "before"
645
- ? rowRect.top - containerRect.top + scrollEl.scrollTop
646
- : rowRect.bottom - containerRect.top + scrollEl.scrollTop;
647
-
648
- indicatorEl.style.display = "block";
649
- indicatorEl.style.top = `${top}px`;
608
+ setDragState({ draggingItem: item, targetItem: foundTarget, position: foundPosition });
609
+
610
+ // 인디케이터 DOM 업데이트
611
+ for (let i = 0; i < rows.length; i++) {
612
+ rows[i].removeAttribute("data-dragging");
613
+ rows[i].removeAttribute("data-drag-over");
614
+
615
+ if (i < displayItems().length) {
616
+ const flat = displayItems()[i];
617
+ if (flat.item === item) {
618
+ rows[i].setAttribute("data-dragging", "");
619
+ }
620
+ if (flat.item === foundTarget && foundPosition === "inside") {
621
+ rows[i].setAttribute("data-drag-over", "inside");
622
+ }
650
623
  }
651
- } else {
652
- indicatorEl.style.display = "none";
653
624
  }
654
- }
655
- };
656
-
657
- const onPointerUp = () => {
658
- const state = dragState();
659
- if (state?.targetItem != null && state.position != null) {
660
- local.onItemsReorder?.({
661
- item: state.draggingItem,
662
- targetItem: state.targetItem,
663
- position: state.position,
664
- } as DataSheetReorderEvent<T>);
665
- }
666
625
 
667
- // 클린업
668
- for (const row of rows) {
669
- row.removeAttribute("data-dragging");
670
- row.removeAttribute("data-drag-over");
671
- }
672
- const indicatorEl = tableEl
673
- .closest("[data-sheet-scroll]")
674
- ?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
675
- if (indicatorEl) {
676
- indicatorEl.style.display = "none";
677
- }
626
+ // before/after 인디케이터
627
+ const indicatorEl = tableEl
628
+ .closest("[data-sheet-scroll]")
629
+ ?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
630
+ if (indicatorEl) {
631
+ if (foundTarget != null && foundPosition != null && foundPosition !== "inside") {
632
+ const targetIdx = displayItems().findIndex((f) => f.item === foundTarget);
633
+ if (targetIdx >= 0) {
634
+ const targetRow = rows[targetIdx];
635
+ const containerRect = tableEl.closest("[data-sheet-scroll]")!.getBoundingClientRect();
636
+ const rowRect = targetRow.getBoundingClientRect();
637
+ const scrollEl = tableEl.closest("[data-sheet-scroll]") as HTMLElement;
638
+
639
+ const top =
640
+ foundPosition === "before"
641
+ ? rowRect.top - containerRect.top + scrollEl.scrollTop
642
+ : rowRect.bottom - containerRect.top + scrollEl.scrollTop;
643
+
644
+ indicatorEl.style.display = "block";
645
+ indicatorEl.style.top = `${top}px`;
646
+ }
647
+ } else {
648
+ indicatorEl.style.display = "none";
649
+ }
650
+ }
651
+ },
652
+ onEnd() {
653
+ const state = dragState();
654
+ if (state?.targetItem != null && state.position != null) {
655
+ local.onItemsReorder?.({
656
+ item: state.draggingItem,
657
+ targetItem: state.targetItem,
658
+ position: state.position,
659
+ } as DataSheetReorderEvent<T>);
660
+ }
678
661
 
679
- setDragState(null);
680
- target.removeEventListener("pointermove", onPointerMove);
681
- target.removeEventListener("pointerup", onPointerUp);
682
- };
662
+ // 클린업
663
+ for (const row of rows) {
664
+ row.removeAttribute("data-dragging");
665
+ row.removeAttribute("data-drag-over");
666
+ }
667
+ const indicatorEl = tableEl
668
+ .closest("[data-sheet-scroll]")
669
+ ?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
670
+ if (indicatorEl) {
671
+ indicatorEl.style.display = "none";
672
+ }
683
673
 
684
- target.addEventListener("pointermove", onPointerMove);
685
- target.addEventListener("pointerup", onPointerUp);
674
+ setDragState(null);
675
+ },
676
+ });
686
677
  }
687
678
 
688
679
  // #region Keyboard Navigation (Enter/Shift+Enter로 행 이동)
@@ -760,8 +751,8 @@ export const DataSheet: DataSheetComponent = <T,>(props: DataSheetProps<T>) => {
760
751
  <div class={toolbarClass}>
761
752
  <Show when={effectivePageCount() > 1}>
762
753
  <Pagination
763
- pageIndex={currentPage()}
764
- onPageIndexChange={setCurrentPage}
754
+ page={currentPage()}
755
+ onPageChange={setCurrentPage}
765
756
  totalPageCount={effectivePageCount()}
766
757
  displayPageCount={local.displayPageCount}
767
758
  size="sm"
@@ -15,8 +15,8 @@ export interface DataSheetProps<TItem> {
15
15
  autoSort?: boolean;
16
16
 
17
17
  // 페이지네이션
18
- pageIndex?: number;
19
- onPageIndexChange?: (pageIndex: number) => void;
18
+ page?: number;
19
+ onPageChange?: (page: number) => void;
20
20
  totalPageCount?: number;
21
21
  itemsPerPage?: number;
22
22
  displayPageCount?: number;
@@ -14,6 +14,7 @@ import { twMerge } from "tailwind-merge";
14
14
  import { IconX } from "@tabler/icons-solidjs";
15
15
  import { createControllableSignal } from "../../hooks/createControllableSignal";
16
16
  import { createMountTransition } from "../../hooks/createMountTransition";
17
+ import { createPointerDrag } from "../../hooks/createPointerDrag";
17
18
  import { mergeStyles } from "../../helpers/mergeStyles";
18
19
  import { Icon } from "../display/Icon";
19
20
  import { borderSubtle } from "../../styles/tokens.styles";
@@ -43,14 +44,14 @@ export interface DialogProps {
43
44
  float?: boolean;
44
45
  /** 전체 화면 모드 */
45
46
  fill?: boolean;
46
- /** 너비 (px) */
47
- widthPx?: number;
48
- /** 높이 (px) */
49
- heightPx?: number;
50
- /** 최소 너비 (px) */
51
- minWidthPx?: number;
52
- /** 최소 높이 (px) */
53
- minHeightPx?: number;
47
+ /** 너비 */
48
+ width?: number;
49
+ /** 높이 */
50
+ height?: number;
51
+ /** 최소 너비 */
52
+ minWidth?: number;
53
+ /** 최소 높이 */
54
+ minHeight?: number;
54
55
  /** 고정 위치 */
55
56
  position?: "bottom-right" | "top-right";
56
57
  /** 헤더 스타일 */
@@ -143,10 +144,10 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
143
144
  "movable",
144
145
  "float",
145
146
  "fill",
146
- "widthPx",
147
- "heightPx",
148
- "minWidthPx",
149
- "minHeightPx",
147
+ "width",
148
+ "height",
149
+ "minWidth",
150
+ "minHeight",
150
151
  "position",
151
152
  "headerStyle",
152
153
  "headerAction",
@@ -256,8 +257,6 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
256
257
  if ((event.target as HTMLElement).closest("button")) return;
257
258
 
258
259
  const target = event.currentTarget as HTMLElement;
259
- target.setPointerCapture(event.pointerId);
260
-
261
260
  const dialogEl = dialogRef;
262
261
  const wrapperEl = wrapperRef;
263
262
 
@@ -266,42 +265,37 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
266
265
  const startTop = dialogEl.offsetTop;
267
266
  const startLeft = dialogEl.offsetLeft;
268
267
 
269
- const doDrag = (e: PointerEvent): void => {
270
- e.stopPropagation();
271
- e.preventDefault();
272
-
273
- dialogEl.style.position = "absolute";
274
- dialogEl.style.left = `${startLeft + e.clientX - startX}px`;
275
- dialogEl.style.top = `${startTop + e.clientY - startY}px`;
276
- dialogEl.style.right = "auto";
277
- dialogEl.style.bottom = "auto";
278
- dialogEl.style.margin = "0";
279
-
280
- // 화면 밖 방지
281
- if (dialogEl.offsetLeft > wrapperEl.offsetWidth - 100) {
282
- dialogEl.style.left = wrapperEl.offsetWidth - 100 + "px";
283
- }
284
- if (dialogEl.offsetTop > wrapperEl.offsetHeight - 100) {
285
- dialogEl.style.top = wrapperEl.offsetHeight - 100 + "px";
286
- }
287
- if (dialogEl.offsetTop < 0) {
288
- dialogEl.style.top = "0";
289
- }
290
- if (dialogEl.offsetLeft < -dialogEl.offsetWidth + 100) {
291
- dialogEl.style.left = -dialogEl.offsetWidth + 100 + "px";
292
- }
293
- };
294
-
295
- const stopDrag = (e: PointerEvent): void => {
296
- e.stopPropagation();
297
- e.preventDefault();
298
-
299
- target.removeEventListener("pointermove", doDrag);
300
- target.removeEventListener("pointerup", stopDrag);
301
- };
302
-
303
- target.addEventListener("pointermove", doDrag);
304
- target.addEventListener("pointerup", stopDrag);
268
+ createPointerDrag(target, event.pointerId, {
269
+ onMove(e) {
270
+ e.stopPropagation();
271
+ e.preventDefault();
272
+
273
+ dialogEl.style.position = "absolute";
274
+ dialogEl.style.left = `${startLeft + e.clientX - startX}px`;
275
+ dialogEl.style.top = `${startTop + e.clientY - startY}px`;
276
+ dialogEl.style.right = "auto";
277
+ dialogEl.style.bottom = "auto";
278
+ dialogEl.style.margin = "0";
279
+
280
+ // 화면 방지
281
+ if (dialogEl.offsetLeft > wrapperEl.offsetWidth - 100) {
282
+ dialogEl.style.left = wrapperEl.offsetWidth - 100 + "px";
283
+ }
284
+ if (dialogEl.offsetTop > wrapperEl.offsetHeight - 100) {
285
+ dialogEl.style.top = wrapperEl.offsetHeight - 100 + "px";
286
+ }
287
+ if (dialogEl.offsetTop < 0) {
288
+ dialogEl.style.top = "0";
289
+ }
290
+ if (dialogEl.offsetLeft < -dialogEl.offsetWidth + 100) {
291
+ dialogEl.style.left = -dialogEl.offsetWidth + 100 + "px";
292
+ }
293
+ },
294
+ onEnd(e) {
295
+ e.stopPropagation();
296
+ e.preventDefault();
297
+ },
298
+ });
305
299
  };
306
300
 
307
301
  // 리사이즈
@@ -310,8 +304,6 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
310
304
  if (!dialogRef) return;
311
305
 
312
306
  const target = event.currentTarget as HTMLElement;
313
- target.setPointerCapture(event.pointerId);
314
-
315
307
  const dialogEl = dialogRef;
316
308
 
317
309
  const startX = event.clientX;
@@ -321,47 +313,42 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
321
313
  const startTop = dialogEl.offsetTop;
322
314
  const startLeft = dialogEl.offsetLeft;
323
315
 
324
- const doDrag = (e: PointerEvent): void => {
325
- e.stopPropagation();
326
- e.preventDefault();
327
-
328
- if (direction === "top" || direction === "top-right" || direction === "top-left") {
329
- if (dialogEl.style.position === "absolute") {
330
- dialogEl.style.top = startTop + (e.clientY - startY) + "px";
331
- dialogEl.style.bottom = "auto";
316
+ createPointerDrag(target, event.pointerId, {
317
+ onMove(e) {
318
+ e.stopPropagation();
319
+ e.preventDefault();
320
+
321
+ if (direction === "top" || direction === "top-right" || direction === "top-left") {
322
+ if (dialogEl.style.position === "absolute") {
323
+ dialogEl.style.top = startTop + (e.clientY - startY) + "px";
324
+ dialogEl.style.bottom = "auto";
325
+ }
326
+ dialogEl.style.height = `${Math.max(startHeight - (e.clientY - startY), local.minHeight ?? 0)}px`;
332
327
  }
333
- dialogEl.style.height = `${Math.max(startHeight - (e.clientY - startY), local.minHeightPx ?? 0)}px`;
334
- }
335
- if (direction === "bottom" || direction === "bottom-right" || direction === "bottom-left") {
336
- dialogEl.style.height = `${Math.max(startHeight + e.clientY - startY, local.minHeightPx ?? 0)}px`;
337
- }
338
- if (direction === "right" || direction === "bottom-right" || direction === "top-right") {
339
- dialogEl.style.width = `${Math.max(
340
- startWidth + (e.clientX - startX) * (dialogEl.style.position === "absolute" ? 1 : 2),
341
- local.minWidthPx ?? 0,
342
- )}px`;
343
- }
344
- if (direction === "left" || direction === "bottom-left" || direction === "top-left") {
345
- if (dialogEl.style.position === "absolute") {
346
- dialogEl.style.left = startLeft + (e.clientX - startX) + "px";
328
+ if (direction === "bottom" || direction === "bottom-right" || direction === "bottom-left") {
329
+ dialogEl.style.height = `${Math.max(startHeight + e.clientY - startY, local.minHeight ?? 0)}px`;
347
330
  }
348
- dialogEl.style.width = `${Math.max(
349
- startWidth - (e.clientX - startX) * (dialogEl.style.position === "absolute" ? 1 : 2),
350
- local.minWidthPx ?? 0,
351
- )}px`;
352
- }
353
- };
354
-
355
- const stopDrag = (e: PointerEvent): void => {
356
- e.stopPropagation();
357
- e.preventDefault();
358
-
359
- target.removeEventListener("pointermove", doDrag);
360
- target.removeEventListener("pointerup", stopDrag);
361
- };
362
-
363
- target.addEventListener("pointermove", doDrag);
364
- target.addEventListener("pointerup", stopDrag);
331
+ if (direction === "right" || direction === "bottom-right" || direction === "top-right") {
332
+ dialogEl.style.width = `${Math.max(
333
+ startWidth + (e.clientX - startX) * (dialogEl.style.position === "absolute" ? 1 : 2),
334
+ local.minWidth ?? 0,
335
+ )}px`;
336
+ }
337
+ if (direction === "left" || direction === "bottom-left" || direction === "top-left") {
338
+ if (dialogEl.style.position === "absolute") {
339
+ dialogEl.style.left = startLeft + (e.clientX - startX) + "px";
340
+ }
341
+ dialogEl.style.width = `${Math.max(
342
+ startWidth - (e.clientX - startX) * (dialogEl.style.position === "absolute" ? 1 : 2),
343
+ local.minWidth ?? 0,
344
+ )}px`;
345
+ }
346
+ },
347
+ onEnd(e) {
348
+ e.stopPropagation();
349
+ e.preventDefault();
350
+ },
351
+ });
365
352
  };
366
353
 
367
354
  // dialog 인라인 스타일 계산
@@ -372,19 +359,19 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
372
359
  style.width = "100%";
373
360
  style.height = "100%";
374
361
  } else {
375
- if (local.widthPx !== undefined) {
376
- style.width = `${local.widthPx}px`;
362
+ if (local.width !== undefined) {
363
+ style.width = `${local.width}px`;
377
364
  }
378
- if (local.heightPx !== undefined) {
379
- style.height = `${local.heightPx}px`;
365
+ if (local.height !== undefined) {
366
+ style.height = `${local.height}px`;
380
367
  }
381
368
  }
382
369
 
383
- if (local.minWidthPx !== undefined) {
384
- style["min-width"] = `${local.minWidthPx}px`;
370
+ if (local.minWidth !== undefined) {
371
+ style["min-width"] = `${local.minWidth}px`;
385
372
  }
386
- if (local.minHeightPx !== undefined) {
387
- style["min-height"] = `${local.minHeightPx}px`;
373
+ if (local.minHeight !== undefined) {
374
+ style["min-height"] = `${local.minHeight}px`;
388
375
  }
389
376
 
390
377
  // position 모드
@@ -497,7 +484,7 @@ export const Dialog: ParentComponent<DialogProps> = (props) => {
497
484
  }
498
485
  onPointerDown={handleHeaderPointerDown}
499
486
  >
500
- <h5 class={clsx("flex-1", "px-4 py-2", "text-sm font-semibold")}>{local.title}</h5>
487
+ <h5 class={clsx("flex-1", "px-4 py-2", "text-sm font-bold")}>{local.title}</h5>
501
488
  {local.headerAction}
502
489
  <Show when={local.closable ?? true}>
503
490
  <button
@@ -17,10 +17,10 @@ export interface DialogShowOptions {
17
17
  movable?: boolean;
18
18
  float?: boolean;
19
19
  fill?: boolean;
20
- widthPx?: number;
21
- heightPx?: number;
22
- minWidthPx?: number;
23
- minHeightPx?: number;
20
+ width?: number;
21
+ height?: number;
22
+ minWidth?: number;
23
+ minHeight?: number;
24
24
  position?: "bottom-right" | "top-right";
25
25
  headerStyle?: JSX.CSSProperties | string;
26
26
  canDeactivate?: () => boolean;
@@ -124,10 +124,10 @@ export const DialogProvider: ParentComponent<DialogProviderProps> = (props) => {
124
124
  movable={entry.options.movable}
125
125
  float={entry.options.float}
126
126
  fill={entry.options.fill}
127
- widthPx={entry.options.widthPx}
128
- heightPx={entry.options.heightPx}
129
- minWidthPx={entry.options.minWidthPx}
130
- minHeightPx={entry.options.minHeightPx}
127
+ width={entry.options.width}
128
+ height={entry.options.height}
129
+ minWidth={entry.options.minWidth}
130
+ minHeight={entry.options.minHeight}
131
131
  position={entry.options.position}
132
132
  headerStyle={entry.options.headerStyle}
133
133
  canDeactivate={entry.options.canDeactivate}