@simplysm/solid 13.0.58 → 13.0.60

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 (79) hide show
  1. package/README.md +1 -1
  2. package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +1 -1
  3. package/dist/components/data/crud-sheet/CrudSheet.js +8 -11
  4. package/dist/components/data/crud-sheet/CrudSheet.js.map +2 -2
  5. package/dist/components/data/crud-sheet/types.d.ts +1 -1
  6. package/dist/components/data/crud-sheet/types.d.ts.map +1 -1
  7. package/dist/components/data/kanban/Kanban.d.ts.map +1 -1
  8. package/dist/components/data/kanban/Kanban.js +3 -4
  9. package/dist/components/data/kanban/Kanban.js.map +2 -2
  10. package/dist/components/data/kanban/KanbanContext.d.ts +2 -3
  11. package/dist/components/data/kanban/KanbanContext.d.ts.map +1 -1
  12. package/dist/components/data/kanban/KanbanContext.js.map +1 -1
  13. package/dist/components/data/list/ListItem.d.ts.map +1 -1
  14. package/dist/components/data/list/ListItem.js +3 -3
  15. package/dist/components/data/list/ListItem.js.map +2 -2
  16. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  17. package/dist/components/disclosure/Dialog.js +3 -4
  18. package/dist/components/disclosure/Dialog.js.map +2 -2
  19. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  20. package/dist/components/disclosure/Dropdown.js +7 -15
  21. package/dist/components/disclosure/Dropdown.js.map +2 -2
  22. package/dist/components/form-control/color-picker/ColorPicker.d.ts +5 -3
  23. package/dist/components/form-control/color-picker/ColorPicker.d.ts.map +1 -1
  24. package/dist/components/form-control/color-picker/ColorPicker.js +11 -6
  25. package/dist/components/form-control/color-picker/ColorPicker.js.map +2 -2
  26. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  27. package/dist/components/form-control/field/NumberInput.js +2 -2
  28. package/dist/components/form-control/field/NumberInput.js.map +2 -2
  29. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  30. package/dist/components/form-control/field/TextInput.js +3 -3
  31. package/dist/components/form-control/field/TextInput.js.map +2 -2
  32. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  33. package/dist/components/form-control/select/Select.js +3 -4
  34. package/dist/components/form-control/select/Select.js.map +2 -2
  35. package/dist/components/form-control/select/SelectContext.d.ts +1 -2
  36. package/dist/components/form-control/select/SelectContext.d.ts.map +1 -1
  37. package/dist/components/form-control/select/SelectContext.js.map +1 -1
  38. package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
  39. package/dist/components/form-control/select/SelectItem.js +3 -3
  40. package/dist/components/form-control/select/SelectItem.js.map +2 -2
  41. package/dist/helpers/createAppStructure.d.ts +7 -4
  42. package/dist/helpers/createAppStructure.d.ts.map +1 -1
  43. package/dist/helpers/createAppStructure.js +20 -2
  44. package/dist/helpers/createAppStructure.js.map +1 -1
  45. package/dist/hooks/createPointerDrag.d.ts +1 -1
  46. package/dist/hooks/createPointerDrag.d.ts.map +1 -1
  47. package/dist/hooks/createPointerDrag.js +6 -4
  48. package/dist/hooks/createPointerDrag.js.map +1 -1
  49. package/dist/hooks/createSlotSignal.d.ts +9 -0
  50. package/dist/hooks/createSlotSignal.d.ts.map +1 -0
  51. package/dist/hooks/createSlotSignal.js +10 -0
  52. package/dist/hooks/createSlotSignal.js.map +6 -0
  53. package/dist/index.d.ts +15 -17
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +15 -39
  56. package/dist/index.js.map +1 -1
  57. package/docs/data-components.md +18 -8
  58. package/docs/feedback.md +8 -2
  59. package/docs/helpers.md +24 -0
  60. package/docs/hooks.md +166 -83
  61. package/docs/styling.md +1 -0
  62. package/package.json +3 -3
  63. package/src/components/data/crud-sheet/CrudSheet.tsx +8 -11
  64. package/src/components/data/crud-sheet/types.ts +1 -1
  65. package/src/components/data/kanban/Kanban.tsx +3 -5
  66. package/src/components/data/kanban/KanbanContext.ts +2 -3
  67. package/src/components/data/list/ListItem.tsx +2 -5
  68. package/src/components/disclosure/Dialog.tsx +3 -6
  69. package/src/components/disclosure/Dropdown.tsx +7 -20
  70. package/src/components/form-control/color-picker/ColorPicker.tsx +19 -9
  71. package/src/components/form-control/field/NumberInput.tsx +2 -4
  72. package/src/components/form-control/field/TextInput.tsx +2 -5
  73. package/src/components/form-control/select/Select.tsx +3 -6
  74. package/src/components/form-control/select/SelectContext.ts +1 -2
  75. package/src/components/form-control/select/SelectItem.tsx +2 -5
  76. package/src/helpers/createAppStructure.ts +36 -6
  77. package/src/hooks/createPointerDrag.ts +8 -5
  78. package/src/hooks/createSlotSignal.ts +14 -0
  79. package/src/index.ts +15 -41
@@ -3,7 +3,7 @@ import clsx from "clsx";
3
3
  import { twMerge } from "tailwind-merge";
4
4
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
5
5
  import { Invalid } from "../Invalid";
6
- import { type ComponentSizeCompact } from "../../../styles/tokens.styles";
6
+ import { type ComponentSize } from "../../../styles/tokens.styles";
7
7
 
8
8
  // 기본 스타일
9
9
  const baseClass = clsx(
@@ -20,13 +20,15 @@ const baseClass = clsx(
20
20
  );
21
21
 
22
22
  // 사이즈별 스타일
23
- const sizeClasses: Record<ComponentSizeCompact, string> = {
23
+ const sizeClasses: Record<ComponentSize, string> = {
24
+ xs: "size-field-xs",
24
25
  sm: "size-field-sm",
25
26
  lg: "size-field-lg",
27
+ xl: "size-field-xl",
26
28
  };
27
29
 
28
30
  // disabled 스타일 - 대각선 줄무늬로 표시
29
- // eslint-disable-next-line tailwindcss/enforces-shorthand -- inset은 Chrome 87+에서만 지원
31
+ // eslint-disable-next-line tailwindcss/enforces-shorthand
30
32
  const disabledClass = clsx(
31
33
  "cursor-default",
32
34
  "relative",
@@ -39,7 +41,7 @@ export interface ColorPickerProps {
39
41
  value?: string;
40
42
 
41
43
  /** 값 변경 콜백 */
42
- onValueChange?: (value: string) => void;
44
+ onValueChange?: (value: string | undefined) => void;
43
45
 
44
46
  /** 타이틀 (툴팁) */
45
47
  title?: string;
@@ -48,7 +50,10 @@ export interface ColorPickerProps {
48
50
  disabled?: boolean;
49
51
 
50
52
  /** 사이즈 */
51
- size?: ComponentSizeCompact;
53
+ size?: ComponentSize;
54
+
55
+ /** inset 모드 (DataSheet 셀 내부 등) */
56
+ inset?: boolean;
52
57
 
53
58
  /** 필수 입력 여부 */
54
59
  required?: boolean;
@@ -81,6 +86,7 @@ export const ColorPicker: Component<ColorPickerProps> = (props) => {
81
86
  "title",
82
87
  "disabled",
83
88
  "size",
89
+ "inset",
84
90
  "required",
85
91
  "validate",
86
92
  "touchMode",
@@ -89,7 +95,7 @@ export const ColorPicker: Component<ColorPickerProps> = (props) => {
89
95
  ]);
90
96
 
91
97
  const [value, setValue] = createControllableSignal({
92
- value: () => local.value ?? "#000000",
98
+ value: () => local.value,
93
99
  onChange: () => local.onValueChange,
94
100
  });
95
101
 
@@ -106,20 +112,24 @@ export const ColorPicker: Component<ColorPickerProps> = (props) => {
106
112
  );
107
113
 
108
114
  const errorMsg = createMemo(() => {
109
- const v = props.value;
115
+ const v = value();
110
116
  if (local.required && (v === undefined || v === "")) return "필수 입력 항목입니다";
111
117
  return local.validate?.(v);
112
118
  });
113
119
 
114
120
  return (
115
- <Invalid variant="border" message={errorMsg()} touchMode={local.touchMode}>
121
+ <Invalid
122
+ variant={local.inset ? "dot" : "border"}
123
+ message={errorMsg()}
124
+ touchMode={local.touchMode}
125
+ >
116
126
  <input
117
127
  {...rest}
118
128
  data-color-picker
119
129
  type="color"
120
130
  class={getClassName()}
121
131
  style={local.style}
122
- value={value()}
132
+ value={value() ?? "#000000"}
123
133
  title={local.title}
124
134
  disabled={local.disabled}
125
135
  onInput={handleInput}
@@ -13,6 +13,7 @@ import {
13
13
  import clsx from "clsx";
14
14
  import { twMerge } from "tailwind-merge";
15
15
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
16
+ import { createSlotSignal, type SlotAccessor } from "../../../hooks/createSlotSignal";
16
17
  import {
17
18
  type FieldSize,
18
19
  fieldInputClass,
@@ -30,8 +31,6 @@ const numberInputClass = clsx(
30
31
  "[&::-webkit-inner-spin-button]:appearance-none",
31
32
  );
32
33
 
33
- type SlotAccessor = (() => JSX.Element) | undefined;
34
-
35
34
  interface NumberInputSlotsContextValue {
36
35
  setPrefix: (content: SlotAccessor) => void;
37
36
  }
@@ -235,8 +234,7 @@ export const NumberInput: NumberInputComponent = (props) => {
235
234
  onChange: () => local.onValueChange,
236
235
  });
237
236
 
238
- const [prefix, _setPrefix] = createSignal<SlotAccessor>();
239
- const setPrefix = (content: SlotAccessor) => _setPrefix(() => content);
237
+ const [prefix, setPrefix] = createSlotSignal();
240
238
  const prefixEl = () => prefix() !== undefined;
241
239
 
242
240
  // 외부 값 변경 시 입력 문자열 동기화
@@ -3,7 +3,6 @@ import {
3
3
  createContext,
4
4
  createEffect,
5
5
  createMemo,
6
- createSignal,
7
6
  type JSX,
8
7
  onCleanup,
9
8
  type ParentComponent,
@@ -13,6 +12,7 @@ import {
13
12
  } from "solid-js";
14
13
  import { twMerge } from "tailwind-merge";
15
14
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
15
+ import { createSlotSignal, type SlotAccessor } from "../../../hooks/createSlotSignal";
16
16
  import { createIMEHandler } from "../../../hooks/createIMEHandler";
17
17
  import {
18
18
  fieldGapClasses,
@@ -23,8 +23,6 @@ import {
23
23
  import { PlaceholderFallback } from "./FieldPlaceholder";
24
24
  import { Invalid } from "../../form-control/Invalid";
25
25
 
26
- type SlotAccessor = (() => JSX.Element) | undefined;
27
-
28
26
  interface TextInputSlotsContextValue {
29
27
  setPrefix: (content: SlotAccessor) => void;
30
28
  }
@@ -244,8 +242,7 @@ const TextInputInner = (props: TextInputProps) => {
244
242
  };
245
243
 
246
244
  // Prefix 슬롯 Context 등록
247
- const [prefix, _setPrefix] = createSignal<SlotAccessor>();
248
- const setPrefix = (content: SlotAccessor) => _setPrefix(() => content);
245
+ const [prefix, setPrefix] = createSlotSignal();
249
246
  const prefixEl = () => prefix() !== undefined;
250
247
 
251
248
  // wrapper 클래스 (includeCustomClass=false일 때 local.class 제외 — inset에서 outer에만 적용)
@@ -21,13 +21,12 @@ import { SelectItem } from "./SelectItem";
21
21
  import { ripple } from "../../../directives/ripple";
22
22
  import { borderDefault, type ComponentSize, textMuted } from "../../../styles/tokens.styles";
23
23
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
24
+ import { createSlotSignal } from "../../../hooks/createSlotSignal";
24
25
  import { chevronWrapperClass, getTriggerClass } from "../DropdownTrigger.styles";
25
26
  import { Invalid } from "../Invalid";
26
27
 
27
28
  void ripple;
28
29
 
29
- type SlotAccessor = (() => JSX.Element) | undefined;
30
-
31
30
  // Select 전용 스타일
32
31
  const multiTagClass = clsx("rounded", "bg-base-200 px-1", "dark:bg-base-600");
33
32
  const selectedValueClass = clsx("flex-1", "whitespace-nowrap");
@@ -272,10 +271,8 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
272
271
  };
273
272
 
274
273
  // 슬롯 signals
275
- const [header, _setHeader] = createSignal<SlotAccessor>();
276
- const setHeader = (content: SlotAccessor) => _setHeader(() => content);
277
- const [action, _setAction] = createSignal<SlotAccessor>();
278
- const setAction = (content: SlotAccessor) => _setAction(() => content);
274
+ const [header, setHeader] = createSlotSignal();
275
+ const [action, setAction] = createSlotSignal();
279
276
  const [itemTemplate, _setItemTemplate] = createSignal<
280
277
  ((...args: unknown[]) => JSX.Element) | undefined
281
278
  >();
@@ -1,6 +1,5 @@
1
1
  import { createContext, useContext, type Accessor, type JSX } from "solid-js";
2
-
3
- type SlotAccessor = (() => JSX.Element) | undefined;
2
+ import type { SlotAccessor } from "../../../hooks/createSlotSignal";
4
3
 
5
4
  export interface SelectContextValue<TValue = unknown> {
6
5
  /** 다중 선택 모드 여부 */
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  createContext,
3
- createSignal,
4
3
  type JSX,
5
4
  onCleanup,
6
5
  type ParentComponent,
@@ -13,6 +12,7 @@ import { IconCheck } from "@tabler/icons-solidjs";
13
12
  import { Icon } from "../../display/Icon";
14
13
  import { useSelectContext } from "./SelectContext";
15
14
  import { ripple } from "../../../directives/ripple";
15
+ import { createSlotSignal, type SlotAccessor } from "../../../hooks/createSlotSignal";
16
16
  import { List } from "../../data/list/List";
17
17
  import { Collapse } from "../../disclosure/Collapse";
18
18
  import {
@@ -26,8 +26,6 @@ import {
26
26
 
27
27
  void ripple;
28
28
 
29
- type SlotAccessor = (() => JSX.Element) | undefined;
30
-
31
29
  interface SelectItemSlotsContextValue {
32
30
  setChildren: (content: SlotAccessor) => void;
33
31
  }
@@ -83,8 +81,7 @@ export const SelectItem: SelectItemComponent = <T,>(
83
81
 
84
82
  const context = useSelectContext<T>();
85
83
 
86
- const [childrenSlot, _setChildrenSlot] = createSignal<SlotAccessor>();
87
- const setChildrenSlot = (content: SlotAccessor) => _setChildrenSlot(() => content);
84
+ const [childrenSlot, setChildrenSlot] = createSlotSignal();
88
85
  const hasChildren = () => childrenSlot() !== undefined;
89
86
  const isSelected = () => context.isSelected(local.value);
90
87
  const useRipple = () => !local.disabled;
@@ -1,5 +1,5 @@
1
- import type { Component } from "solid-js";
2
- import { type Accessor, createMemo, createRoot } from "solid-js";
1
+ import type { Component, ParentComponent } from "solid-js";
2
+ import { type Accessor, createContext, createMemo, createRoot, useContext } from "solid-js";
3
3
  import type { IconProps } from "@tabler/icons-solidjs";
4
4
 
5
5
  // ── 입력 타입 ──
@@ -412,10 +412,7 @@ function findItemChainByCodes<TModule>(
412
412
 
413
413
  // ── 메인 함수 ──
414
414
 
415
- export function createAppStructure<
416
- TModule,
417
- const TItems extends AppStructureItem<TModule>[],
418
- >(opts: {
415
+ function buildAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(opts: {
419
416
  items: TItems;
420
417
  usableModules?: Accessor<TModule[] | undefined>;
421
418
  permRecord?: Accessor<Record<string, boolean> | undefined>;
@@ -481,3 +478,36 @@ export function createAppStructure<
481
478
  },
482
479
  };
483
480
  }
481
+
482
+ export function createAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(
483
+ getOpts: () => {
484
+ items: TItems;
485
+ usableModules?: Accessor<TModule[] | undefined>;
486
+ permRecord?: Accessor<Record<string, boolean> | undefined>;
487
+ },
488
+ ): {
489
+ AppStructureProvider: ParentComponent;
490
+ useAppStructure: () => AppStructure<TModule> & { perms: InferPerms<TItems> };
491
+ } {
492
+ type TRet = AppStructure<TModule> & { perms: InferPerms<TItems> };
493
+
494
+ const Ctx = createContext<TRet>();
495
+
496
+ const AppStructureProvider: ParentComponent = (props) => {
497
+ const structure = buildAppStructure(getOpts());
498
+ return Ctx.Provider({
499
+ value: structure as TRet,
500
+ get children() {
501
+ return props.children;
502
+ },
503
+ });
504
+ };
505
+
506
+ const useAppStructure = (): TRet => {
507
+ const ctx = useContext(Ctx);
508
+ if (!ctx) throw new Error("AppStructureProvider가 필요합니다.");
509
+ return ctx;
510
+ };
511
+
512
+ return { AppStructureProvider, useAppStructure };
513
+ }
@@ -4,7 +4,7 @@
4
4
  * @param target - Element to capture pointer on
5
5
  * @param pointerId - Pointer ID from the initiating PointerEvent
6
6
  * @param options.onMove - Called on each pointermove
7
- * @param options.onEnd - Called on pointerup (after listener cleanup)
7
+ * @param options.onEnd - Called on pointerup or pointercancel (after listener cleanup)
8
8
  */
9
9
  export function createPointerDrag(
10
10
  target: HTMLElement,
@@ -16,13 +16,16 @@ export function createPointerDrag(
16
16
  ): void {
17
17
  target.setPointerCapture(pointerId);
18
18
 
19
- const onPointerMove = (e: PointerEvent) => options.onMove(e);
20
- const onPointerUp = (e: PointerEvent) => {
19
+ const cleanup = (e: PointerEvent) => {
21
20
  target.removeEventListener("pointermove", onPointerMove);
22
- target.removeEventListener("pointerup", onPointerUp);
21
+ target.removeEventListener("pointerup", cleanup);
22
+ target.removeEventListener("pointercancel", cleanup);
23
23
  options.onEnd(e);
24
24
  };
25
25
 
26
+ const onPointerMove = (e: PointerEvent) => options.onMove(e);
27
+
26
28
  target.addEventListener("pointermove", onPointerMove);
27
- target.addEventListener("pointerup", onPointerUp);
29
+ target.addEventListener("pointerup", cleanup);
30
+ target.addEventListener("pointercancel", cleanup);
28
31
  }
@@ -0,0 +1,14 @@
1
+ import { createSignal, type Accessor, type JSX } from "solid-js";
2
+
3
+ export type SlotAccessor = (() => JSX.Element) | undefined;
4
+
5
+ /**
6
+ * 슬롯 등록용 signal 생성
7
+ *
8
+ * @returns [accessor, setter] — setter는 함수를 값으로 저장하기 위해 래핑 처리
9
+ */
10
+ export function createSlotSignal(): [Accessor<SlotAccessor>, (content: SlotAccessor) => void] {
11
+ const [slot, _setSlot] = createSignal<SlotAccessor>();
12
+ const setSlot = (content: SlotAccessor) => _setSlot(() => content);
13
+ return [slot, setSlot];
14
+ }
package/src/index.ts CHANGED
@@ -115,37 +115,22 @@ export * from "./components/feedback/Progress";
115
115
  //#region ========== Providers ==========
116
116
 
117
117
  // Config
118
- export { type AppConfig, ConfigContext, useConfig } from "./providers/ConfigContext";
118
+ export * from "./providers/ConfigContext";
119
119
 
120
120
  // SyncStorage
121
- export {
122
- type StorageAdapter,
123
- type SyncStorageContextValue,
124
- SyncStorageContext,
125
- useSyncStorage,
126
- } from "./providers/SyncStorageContext";
121
+ export * from "./providers/SyncStorageContext";
127
122
 
128
123
  // Logger
129
- export { type LogAdapter, type LoggerContextValue } from "./providers/LoggerContext";
124
+ export * from "./providers/LoggerContext";
130
125
 
131
126
  // Theme
132
- export { useTheme } from "./providers/ThemeContext";
133
- export type { ThemeMode, ResolvedTheme } from "./providers/ThemeContext";
127
+ export * from "./providers/ThemeContext";
134
128
 
135
129
  // ServiceClient
136
- export {
137
- type ServiceClientContextValue,
138
- ServiceClientContext,
139
- useServiceClient,
140
- } from "./providers/ServiceClientContext";
130
+ export * from "./providers/ServiceClientContext";
141
131
 
142
132
  // SharedData
143
- export type {
144
- SharedDataDefinition,
145
- SharedDataAccessor,
146
- SharedDataValue,
147
- } from "./providers/shared-data/SharedDataContext";
148
- export { SharedDataContext, useSharedData } from "./providers/shared-data/SharedDataContext";
133
+ export * from "./providers/shared-data/SharedDataContext";
149
134
  export * from "./providers/shared-data/SharedDataChangeEvent";
150
135
 
151
136
  // SystemProvider
@@ -158,11 +143,12 @@ export * from "./providers/SystemProvider";
158
143
  export * from "./hooks/useLocalStorage";
159
144
  export * from "./hooks/useSyncConfig";
160
145
  export * from "./hooks/useLogger";
161
- export { createControllableSignal } from "./hooks/createControllableSignal";
162
- export { createControllableStore } from "./hooks/createControllableStore";
163
- export { createIMEHandler } from "./hooks/createIMEHandler";
164
- export { createMountTransition } from "./hooks/createMountTransition";
165
- export { useRouterLink } from "./hooks/useRouterLink";
146
+ export * from "./hooks/createControllableSignal";
147
+ export * from "./hooks/createControllableStore";
148
+ export * from "./hooks/createIMEHandler";
149
+ export * from "./hooks/createMountTransition";
150
+ export * from "./hooks/createSlotSignal";
151
+ export * from "./hooks/useRouterLink";
166
152
 
167
153
  //#endregion
168
154
 
@@ -175,25 +161,13 @@ export * from "./styles/patterns.styles";
175
161
 
176
162
  //#region ========== Directives ==========
177
163
 
178
- export { ripple } from "./directives/ripple";
164
+ export * from "./directives/ripple";
179
165
 
180
166
  //#endregion
181
167
 
182
168
  //#region ========== Helpers ==========
183
169
 
184
- export { mergeStyles } from "./helpers/mergeStyles";
185
- export { createAppStructure } from "./helpers/createAppStructure";
186
- export type {
187
- AppStructureItem,
188
- AppStructureGroupItem,
189
- AppStructureLeafItem,
190
- AppStructureSubPerm,
191
- AppRoute,
192
- AppFlatMenu,
193
- AppMenu,
194
- AppPerm,
195
- AppFlatPerm,
196
- AppStructure,
197
- } from "./helpers/createAppStructure";
170
+ export * from "./helpers/mergeStyles";
171
+ export * from "./helpers/createAppStructure";
198
172
 
199
173
  //#endregion