@simplysm/solid 13.0.95 → 13.0.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/layout/sidebar/Sidebar.d.ts +5 -0
- package/dist/components/layout/sidebar/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/sidebar/Sidebar.js +7 -4
- package/dist/components/layout/sidebar/Sidebar.js.map +2 -2
- package/package.json +19 -26
- package/src/components/layout/sidebar/Sidebar.tsx +9 -3
- package/README.md +0 -145
- package/docs/display-feedback.md +0 -279
- package/docs/features.md +0 -653
- package/docs/form-controls.md +0 -378
- package/docs/layout-data.md +0 -386
- package/docs/providers-hooks.md +0 -411
package/docs/providers-hooks.md
DELETED
|
@@ -1,411 +0,0 @@
|
|
|
1
|
-
# 프로바이더 & 훅
|
|
2
|
-
|
|
3
|
-
## SystemProvider
|
|
4
|
-
|
|
5
|
-
모든 필수 프로바이더를 한 번에 감싸는 편의 컴포넌트. 대부분의 앱에서는 이것 하나로 충분하다.
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { SystemProvider } from "@simplysm/solid";
|
|
9
|
-
|
|
10
|
-
<SystemProvider clientName="my-app" busyVariant="spinner">
|
|
11
|
-
<App />
|
|
12
|
-
</SystemProvider>
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| Prop | 타입 | 설명 |
|
|
16
|
-
|------|------|------|
|
|
17
|
-
| `clientName` | `string` | 클라이언트 식별 이름 (localStorage 키 접두사 등에 사용) |
|
|
18
|
-
| `busyVariant` | `"spinner" \| "bar"` | 글로벌 BusyProvider 변형 |
|
|
19
|
-
|
|
20
|
-
내부 프로바이더 스택 (위에서 아래 순서):
|
|
21
|
-
`ConfigProvider` > `I18nProvider` > `SyncStorageProvider` > `LoggerProvider` > `NotificationProvider` + `NotificationBanner` > `ErrorLoggerProvider` > `PwaUpdateProvider` > `ClipboardProvider` > `ThemeProvider` > `ServiceClientProvider` > `SharedDataProvider` > `BusyProvider`
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## ThemeProvider
|
|
26
|
-
|
|
27
|
-
라이트/다크/시스템 테마 관리. localStorage에 설정 저장.
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { ThemeProvider, useTheme } from "@simplysm/solid";
|
|
31
|
-
|
|
32
|
-
<ThemeProvider>
|
|
33
|
-
<App />
|
|
34
|
-
</ThemeProvider>
|
|
35
|
-
|
|
36
|
-
const theme = useTheme();
|
|
37
|
-
|
|
38
|
-
theme.mode(); // "light" | "dark" | "system"
|
|
39
|
-
theme.resolvedTheme(); // "light" | "dark" (OS 설정 반영)
|
|
40
|
-
theme.setMode("dark");
|
|
41
|
-
theme.cycleMode(); // light → system → dark → light
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## I18nProvider
|
|
47
|
-
|
|
48
|
-
다국어 지원. 한국어(ko), 영어(en) 내장.
|
|
49
|
-
|
|
50
|
-
```tsx
|
|
51
|
-
import { I18nProvider, useI18n } from "@simplysm/solid";
|
|
52
|
-
|
|
53
|
-
<I18nProvider>
|
|
54
|
-
<App />
|
|
55
|
-
</I18nProvider>
|
|
56
|
-
|
|
57
|
-
const i18n = useI18n();
|
|
58
|
-
|
|
59
|
-
i18n.t("save"); // 번역 조회
|
|
60
|
-
i18n.t("greeting", { name: "Alice" }); // 파라미터 치환
|
|
61
|
-
i18n.locale(); // 현재 로케일
|
|
62
|
-
i18n.setLocale("en");
|
|
63
|
-
|
|
64
|
-
// 사전 확장
|
|
65
|
-
i18n.configure({
|
|
66
|
-
dictionaries: {
|
|
67
|
-
ko: { myKey: "내 값" },
|
|
68
|
-
en: { myKey: "My Value" },
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## SharedDataProvider
|
|
76
|
-
|
|
77
|
-
서버 데이터를 구독하고 실시간 동기화하는 프로바이더. `ServiceClientProvider`와 `NotificationProvider` 내부에서 사용해야 한다.
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
import { SharedDataProvider, useSharedData } from "@simplysm/solid";
|
|
81
|
-
|
|
82
|
-
// 프로바이더 설정 (SystemProvider 사용 시 자동 포함)
|
|
83
|
-
<SharedDataProvider>
|
|
84
|
-
<App />
|
|
85
|
-
</SharedDataProvider>
|
|
86
|
-
|
|
87
|
-
// 데이터 정의 (자식 컴포넌트에서 한 번만 호출)
|
|
88
|
-
const sharedData = useSharedData<{
|
|
89
|
-
users: User;
|
|
90
|
-
departments: Department;
|
|
91
|
-
}>();
|
|
92
|
-
|
|
93
|
-
sharedData.configure(() => ({
|
|
94
|
-
users: {
|
|
95
|
-
fetch: async (changeKeys) => await api.getUsers(changeKeys),
|
|
96
|
-
getKey: (item) => item.id,
|
|
97
|
-
orderBy: [[(item) => item.name, "asc"]],
|
|
98
|
-
itemSearchText: (item) => item.name,
|
|
99
|
-
isItemHidden: (item) => item.isDeleted,
|
|
100
|
-
},
|
|
101
|
-
departments: {
|
|
102
|
-
fetch: async (changeKeys) => await api.getDepartments(changeKeys),
|
|
103
|
-
getKey: (item) => item.id,
|
|
104
|
-
orderBy: [[(item) => item.sortOrder, "asc"]],
|
|
105
|
-
getParentKey: (item) => item.parentId, // 트리 구조 지원
|
|
106
|
-
},
|
|
107
|
-
}));
|
|
108
|
-
|
|
109
|
-
// 데이터 사용
|
|
110
|
-
const users = sharedData.users.items(); // 반응형 배열
|
|
111
|
-
const user = sharedData.users.get(userId); // 키로 조회
|
|
112
|
-
|
|
113
|
-
// 변경 이벤트 발행 (서버의 모든 구독자에게 전파)
|
|
114
|
-
await sharedData.users.emit([changedUserId]);
|
|
115
|
-
|
|
116
|
-
// 전체 로딩 대기
|
|
117
|
-
await sharedData.wait();
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### SharedDataDefinition
|
|
121
|
-
|
|
122
|
-
| 속성 | 타입 | 설명 |
|
|
123
|
-
|------|------|------|
|
|
124
|
-
| `fetch` | `(changeKeys?) => Promise<TData[]>` | 데이터 조회 함수 |
|
|
125
|
-
| `getKey` | `(item) => string \| number` | 항목 고유 키 추출 |
|
|
126
|
-
| `orderBy` | `[(item) => unknown, "asc" \| "desc"][]` | 정렬 기준 (다중) |
|
|
127
|
-
| `serviceKey` | `string` | 서비스 연결 키 (기본: `"default"`) |
|
|
128
|
-
| `filter` | `unknown` | 서버 이벤트 필터 |
|
|
129
|
-
| `itemSearchText` | `(item) => string` | 검색 텍스트 추출 |
|
|
130
|
-
| `isItemHidden` | `(item) => boolean` | 숨김 여부 |
|
|
131
|
-
| `getParentKey` | `(item) => string \| number \| undefined` | 부모 키 (트리 구조) |
|
|
132
|
-
|
|
133
|
-
### SharedDataAccessor
|
|
134
|
-
|
|
135
|
-
| 메서드/속성 | 타입 | 설명 |
|
|
136
|
-
|------------|------|------|
|
|
137
|
-
| `items()` | `Accessor<TData[]>` | 반응형 데이터 배열 |
|
|
138
|
-
| `get(key)` | `(key) => TData \| undefined` | 키로 단건 조회 |
|
|
139
|
-
| `emit(changeKeys?)` | `(keys?) => Promise<void>` | 변경 이벤트 발행 |
|
|
140
|
-
| `getKey` | `(item) => string \| number` | 키 추출 함수 |
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## 기타 프로바이더
|
|
145
|
-
|
|
146
|
-
| 프로바이더 | 설명 |
|
|
147
|
-
|-----------|------|
|
|
148
|
-
| `ConfigProvider` | 클라이언트 설정 (localStorage 키 접두사). prop: `clientName: string` |
|
|
149
|
-
| `ServiceClientProvider` | `@simplysm/service-client` WebSocket 연결 통합 |
|
|
150
|
-
| `SyncStorageProvider` | localStorage 동기화 |
|
|
151
|
-
| `LoggerProvider` | 로깅 설정 |
|
|
152
|
-
| `ErrorLoggerProvider` | 글로벌 에러 핸들링 (window.onerror 등) |
|
|
153
|
-
| `ClipboardProvider` | 클립보드 기능 |
|
|
154
|
-
| `PwaUpdateProvider` | PWA Service Worker 업데이트 감지 (5분 간격 폴링, 알림 표시) |
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## 훅
|
|
159
|
-
|
|
160
|
-
### createControllableSignal
|
|
161
|
-
|
|
162
|
-
제어/비제어 컴포넌트 패턴 구현.
|
|
163
|
-
|
|
164
|
-
```typescript
|
|
165
|
-
import { createControllableSignal } from "@simplysm/solid";
|
|
166
|
-
|
|
167
|
-
const [value, setValue] = createControllableSignal({
|
|
168
|
-
value: () => props.value,
|
|
169
|
-
onChange: () => props.onValueChange,
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### createControllableStore
|
|
174
|
-
|
|
175
|
-
객체 상태용 제어/비제어 패턴.
|
|
176
|
-
|
|
177
|
-
### createIMEHandler
|
|
178
|
-
|
|
179
|
-
IME(한글 등) 입력 처리.
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
const ime = createIMEHandler();
|
|
183
|
-
// ime.handleCompositionStart()
|
|
184
|
-
// ime.handleCompositionEnd()
|
|
185
|
-
// ime.handleInput()
|
|
186
|
-
// ime.composingValue()
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### useLocalStorage
|
|
190
|
-
|
|
191
|
-
반응형 localStorage.
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
import { useLocalStorage } from "@simplysm/solid";
|
|
195
|
-
|
|
196
|
-
const [theme, setTheme] = useLocalStorage("theme", "light");
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### useSyncConfig
|
|
200
|
-
|
|
201
|
-
클라이언트명 접두사 붙은 localStorage 동기화.
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
const [config, setConfig] = useSyncConfig("my-setting", defaultValue);
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### useLogger
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
const logger = useLogger();
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### useRouterLink
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
const navigate = useRouterLink();
|
|
217
|
-
navigate("/users");
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### createMountTransition
|
|
221
|
-
|
|
222
|
-
마운트 애니메이션 상태 관리.
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
const { mounted, animating, unmount } = createMountTransition(() => isVisible());
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## createAppStructure
|
|
231
|
-
|
|
232
|
-
앱 메뉴, 라우트, 권한 구조를 선언적으로 정의한다. 모듈별 필터링과 권한 기반 접근 제어를 지원한다.
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
import { createAppStructure } from "@simplysm/solid";
|
|
236
|
-
import type { AppStructureItem } from "@simplysm/solid";
|
|
237
|
-
|
|
238
|
-
type Module = "basic" | "pro" | "enterprise";
|
|
239
|
-
|
|
240
|
-
const items: AppStructureItem<Module>[] = [
|
|
241
|
-
{
|
|
242
|
-
code: "admin",
|
|
243
|
-
title: "관리",
|
|
244
|
-
children: [
|
|
245
|
-
{
|
|
246
|
-
code: "users",
|
|
247
|
-
title: "사용자 관리",
|
|
248
|
-
component: UserPage,
|
|
249
|
-
perms: ["use", "edit"],
|
|
250
|
-
modules: ["basic"],
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
code: "roles",
|
|
254
|
-
title: "역할 관리",
|
|
255
|
-
component: RolePage,
|
|
256
|
-
perms: ["use", "edit"],
|
|
257
|
-
modules: ["pro"],
|
|
258
|
-
subPerms: [
|
|
259
|
-
{ code: "advanced", title: "고급 설정", perms: ["use", "edit"], modules: ["enterprise"] },
|
|
260
|
-
],
|
|
261
|
-
},
|
|
262
|
-
],
|
|
263
|
-
},
|
|
264
|
-
];
|
|
265
|
-
|
|
266
|
-
const { AppStructureProvider, useAppStructure } = createAppStructure(() => ({
|
|
267
|
-
items,
|
|
268
|
-
usableModules: () => activeModules(),
|
|
269
|
-
permRecord: () => userPermissions(),
|
|
270
|
-
}));
|
|
271
|
-
|
|
272
|
-
// 프로바이더 설정
|
|
273
|
-
<AppStructureProvider>
|
|
274
|
-
<App />
|
|
275
|
-
</AppStructureProvider>
|
|
276
|
-
|
|
277
|
-
// 사용
|
|
278
|
-
const app = useAppStructure();
|
|
279
|
-
|
|
280
|
-
app.usableRoutes(); // 접근 가능한 라우트 배열
|
|
281
|
-
app.usableMenus(); // 접근 가능한 메뉴 트리
|
|
282
|
-
app.usableFlatMenus(); // 플랫 메뉴 배열 (검색용)
|
|
283
|
-
app.usablePerms(); // 권한 트리 (PermissionTable에 전달)
|
|
284
|
-
app.allFlatPerms; // 모든 권한 목록 (관리용)
|
|
285
|
-
app.perms; // 타입 안전한 권한 객체 (app.perms.admin.users.use)
|
|
286
|
-
|
|
287
|
-
app.getTitleChainByHref("/admin/users"); // ["관리", "사용자 관리"]
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### AppStructure 반환 타입
|
|
291
|
-
|
|
292
|
-
| 속성 | 타입 | 설명 |
|
|
293
|
-
|------|------|------|
|
|
294
|
-
| `usableRoutes` | `Accessor<AppRoute[]>` | 모듈/권한 필터링된 라우트 |
|
|
295
|
-
| `usableMenus` | `Accessor<AppMenu[]>` | 필터링된 메뉴 트리 |
|
|
296
|
-
| `usableFlatMenus` | `Accessor<AppFlatMenu[]>` | 플랫 메뉴 배열 |
|
|
297
|
-
| `usablePerms` | `Accessor<AppPerm[]>` | 필터링된 권한 트리 |
|
|
298
|
-
| `allFlatPerms` | `AppFlatPerm[]` | 전체 권한 목록 |
|
|
299
|
-
| `perms` | `InferPerms<TItems>` | 타입 추론된 권한 접근 객체 |
|
|
300
|
-
| `getTitleChainByHref` | `(href: string) => string[]` | href로 타이틀 체인 조회 |
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## 스타일 유틸리티
|
|
305
|
-
|
|
306
|
-
### 기본 스타일
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
import { bg, border, text } from "@simplysm/solid";
|
|
310
|
-
|
|
311
|
-
// Tailwind 클래스 프리셋
|
|
312
|
-
bg.surface // bg-white dark:bg-base-900
|
|
313
|
-
bg.muted // bg-base-100 dark:bg-base-800
|
|
314
|
-
bg.subtle // bg-base-200 dark:bg-base-700
|
|
315
|
-
border.default // border-base-200 dark:border-base-700
|
|
316
|
-
text.default // text-base-900 dark:text-base-100
|
|
317
|
-
text.muted // text-base-400 dark:text-base-500
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### 컨트롤 스타일
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
import { pad, gap } from "@simplysm/solid";
|
|
324
|
-
|
|
325
|
-
pad.xs // px-1 py-0
|
|
326
|
-
pad.sm // px-1.5 py-0.5
|
|
327
|
-
pad.md // px-2 py-1
|
|
328
|
-
pad.lg // px-3 py-2
|
|
329
|
-
pad.xl // px-4 py-3
|
|
330
|
-
|
|
331
|
-
gap.xs // gap-0
|
|
332
|
-
gap.sm // gap-0.5
|
|
333
|
-
gap.md // gap-1
|
|
334
|
-
gap.lg // gap-1.5
|
|
335
|
-
gap.xl // gap-2
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
### 테마 토큰
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
import { themeTokens, type SemanticTheme } from "@simplysm/solid";
|
|
342
|
-
|
|
343
|
-
// 각 semantic theme(base, primary, success, warning, danger, info)별:
|
|
344
|
-
themeTokens.primary.solid // bg-primary-500 text-white
|
|
345
|
-
themeTokens.primary.solidHover // hover:bg-primary-600 dark:hover:bg-primary-400
|
|
346
|
-
themeTokens.primary.light // bg-primary-100 text-primary-900 ...
|
|
347
|
-
themeTokens.primary.text // text-primary-600 dark:text-primary-400
|
|
348
|
-
themeTokens.primary.hoverBg // hover:bg-primary-100 ...
|
|
349
|
-
themeTokens.primary.border // border-primary-300 ...
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
---
|
|
353
|
-
|
|
354
|
-
## 디렉티브
|
|
355
|
-
|
|
356
|
-
### ripple
|
|
357
|
-
|
|
358
|
-
Material Design 스타일 리플 효과.
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
import { ripple } from "@simplysm/solid";
|
|
362
|
-
|
|
363
|
-
<button use:ripple>클릭</button>
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
## 헬퍼
|
|
369
|
-
|
|
370
|
-
### mergeStyles
|
|
371
|
-
|
|
372
|
-
인라인 CSS 문자열 병합.
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
import { mergeStyles } from "@simplysm/solid";
|
|
376
|
-
|
|
377
|
-
mergeStyles("color: red", "font-size: 14px"); // "color: red; font-size: 14px"
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### createSlot / createSlots
|
|
381
|
-
|
|
382
|
-
컴포넌트 합성을 위한 슬롯 패턴. `createSlot`은 단일 슬롯, `createSlots`는 복수 슬롯을 지원한다.
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
import { createSlot } from "@simplysm/solid";
|
|
386
|
-
|
|
387
|
-
// 슬롯 정의
|
|
388
|
-
const [MySlot, createMySlotAccessor] = createSlot<{ children: JSX.Element }>();
|
|
389
|
-
|
|
390
|
-
// 컴포넌트 내부에서 슬롯 접근
|
|
391
|
-
const [slotValue, SlotProvider] = createMySlotAccessor();
|
|
392
|
-
|
|
393
|
-
// 사용
|
|
394
|
-
<SlotProvider>
|
|
395
|
-
<MySlot><span>슬롯 내용</span></MySlot>
|
|
396
|
-
{/* slotValue()로 접근 */}
|
|
397
|
-
</SlotProvider>
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
### startPointerDrag
|
|
401
|
-
|
|
402
|
-
포인터 드래그 인터랙션 관리. 포인터 캡처를 설정하고 move/end 이벤트를 관리한다.
|
|
403
|
-
|
|
404
|
-
```typescript
|
|
405
|
-
import { startPointerDrag } from "@simplysm/solid";
|
|
406
|
-
|
|
407
|
-
startPointerDrag(element, event.pointerId, {
|
|
408
|
-
onMove: (e) => { /* 드래그 중 */ },
|
|
409
|
-
onEnd: (e) => { /* 드래그 종료 */ },
|
|
410
|
-
});
|
|
411
|
-
```
|